Здесь приведен перевод апноута AVR115: Data Logging with Atmel File System on ATmega32U4 [1], посвященного практическому применению файловой системы Atmel для микроконтроллеров. Файловая система Atmel File System [2] предназначена (оптимизирована) для микроконтроллеров серий AT90USBx и ATmegaxxUx. Эта файловая система позволяет организовать лог для данных, и в этом апноуте показано, как такое реализовать на примере использования ATmega32U4, установленного на отладочной плате EVK527. Готовый проект firmware EVK527-series4-datalogging-2_0_1 можно скачать в архиве [3]. Для лучшего понимания материала рекомендуется ознакомление с апноутом AVR114 [2].
Прим. переводчика: в библиотеке LUFA есть аналогичный проект, записывающий данные температуры (см. архив LUFA, папка Projects\TempDataLogger). Сохранение данных можно организовать также на основе любой макетной платы, например [6], если в качестве носителя данных использовать к примеру стандартную карту SD/MMC, подключенную к микроконтроллеру через интерфейс SPI.
[2 Требования к аппаратуре]
Пример приложения для сбора данных (Data Logging) требует для себя следующее железо (hardware):
• Отладочную плату ATEVK527 для микроконтроллеров серий AVR, которая включает в себя: - микроконтроллер ATmega32U4 - носитель данных DataFlash® (32 мегабита) - слот для карт SD/MMC • Кабель USB (стандартный, коннектор A < -- > коннектор Mini B). • Компьютер PC, работающий на операционной системе Windows® (98SE, ME, 2000, XP), Linux® или MAC® OS, с портом USB, поддерживающим стандарт хоста 1.1 или 2.0.
[3 Чем программировать (прошивать) ATmega32U4]
Для того, чтобы прошить память микроконтроллера, Вы можете использовать следующие методы:
• Интерфейс JTAG, для этого нужен аппаратный отладчик JTAGICE mkII [4](2). • Интерфейс ISP (SPI), для этого можно использовать программаторы AVRISP mkII, AVR Dragon (прим. переводчика: и множество других программаторов [5]) и отладчик JTAGICE mkII(2). • Интерфейс USB, благодаря прошитому в память микроконтроллера (это уже сделано на заводе Atmel) DFU bootloader и программному обеспечению FLIP(1). Этот способ наиболее практичен и удобен. • Параллельное программирование, для этого нужны программаторы STK®500 или STK600.
Примечания: (1) Программа-утилита FLIP предоставляется компанией Atmel, чтобы позволить пользователю прошить устройства AVR USB (и другие) через подключение USB, что не требует никакой дополнительной аппаратуры типа отладчиков и программаторов. Прием данных через USB и перепрошивку памяти программ берет на себя бутлоадер DFU, заранее прошитый в память чипа на заводе Atmel. (2) При использовании JTAGICE MKII будьте осторожны с галочкой "erase before programming" (очистить перед программированием) в утилите программатора AVR Studio®. Если эта галочка установлена, то это приведет к стиранию как программы пользователя, так и к стиранию бутлоадера DFU. Прим. переводчика: при необходимости бутлоадер всегда можно восстановить с помощью ISP-программатора, бинарник бутлоадера можно скачать с сайта Atmel.
Пожалуйста обратитесь к содержимому справки FLIP для того, чтобы узнать, как установить драйвер USB и как запрограммировать микроконтроллер ATmega32U4 через интерфейс USB.
Прим. переводчика: простые указания на русском языке по установке драйвера USB и перепрошивке микроконтроллера через FLIP можно получить из статьи "Макетная плата AVR-USB32U4" [6].
[4 Быстрый старт]
Как только прошили Ваш микроконтроллер ATmega32U4 HEX-файлом проекта EVK527-series4-datalogging [3], Вы можете запустить демонстрацию сбора данных (data logging):
1. Отключите кабель USB и подключите кабель питания (9V). 2. Нажмите клавишу для старта записи: • Будет создан файл лога либо на карте MMC/SD (если она установлена в слот), или в память DataFlash. • когда запись начнется, загорится светодиод LED0. • Светодиод LED2 загорится, если произойдет какая-либо ошибка (диск не найден, переполнен, и т. п.). 3. Для остановки записи нажмите кнопку HWB или подключите кабель USB. 4. Подключите кабель USB к компьютеру PC, чтобы запустить U-Disk, и прочитать лог-файл "Disk:\log000\log000.bin"
Рис. 4-1. Отладочная плата EVK527 Rev1.
Примечание: это заводская конфигурация платы EVK527 по умолчанию, за исключением того, что нужно запаять перемычки SP2 и SP4 (чтобы разрешить работу светодиодов LED0 и LED2).
По умолчанию записываемые данные содержат только 16-битное число, инкрементируемое каждые 120 мкс. Это можно изменить, и задать источник данных через опции времени компиляции в файле datalogging.c:
#define LOG_ADCMIC_EXAMPLE // От ADC микрофона в файл WAV
#define LOG_ADCEXT_EXAMPLE // От другого входа ADC в файл BIN
#define LOG_PIN_EXAMPLE // Записать состояние ножек в файл BIN
#define LOG_ENUM_EXAMPLE // Записывать значение счетчика в файл BIN (по умолчанию)
[5 Описание работы приложения EVK527-series4-datalogging]
5.1 Как это работает
Пример приложения firmware предоставляет 2 рабочих режима:
Download mode (режим загрузки): пользователь подключает EVK527 к компьютеру PC через USB (получая при этом извлекаемый виртуальный диск "U-Disk", USB Mass Storage Device), чтобы получить доступ к лог-файлу, записанному в имеющиеся носители данных (это может быть запаянная на плате память DataFlash, или стандартная карта SD/MMC, установленная в слот). В этом режиме встроенная в firmware Atmel File System не имеет доступа к носителям данных, и файл лога не может быть создан записан микроконтроллером.
Примечание: это сделано специально, чтобы предотвратить повреждение данных - в любой момент времени только одна файловая система (или только MassStorage Device, поддерживаемая операционной системой Windows, или только Atmel File System, работающая в firmware микроконтроллера ATmega32U4) может получить доступ к носителю данных.
Рис. 5-1. Режим загрузки, Download mode (U-Disk).
Data logging mode (режим сбора данных): когда активен этот режим, то в файл могут быть записаны какие-либо данные. Кит EVK527 отключен от хоста USB (компьютера), и может начать/остановить запись, если нажать соответствующие кнопки EVK527 (см. рис 4-1). Когда запись началась, то файл создается на носителе данных. Таймер создает прерывания с частотой 8 кГц, и обработчик прерывания таймера делает выборки сигнала со входа канала ADC (ЦАП), или другого источника данных, и записывает их в буфер SRAM. Заполненные буферы переносятся в файл лога, эту работу выполняет задача логгинга (data logging task).
Рис 5-2. Режим сбора данных, Data Logging mode.
5.2 Firmware
Эта секция разъясняет только работу файловой системы Atmel, и не касается модуля USB. Приведенные примеры кода взяты из файла data_logging.c проекта EVK527-series4-datalogging [3].
5.2.1 Разрешение/запрет работы встроенной файловой системы
Инициализация модуля File System и выход из него управляется задачей datalogging_task(). Когда чип выходит из режима USB Device (в котором оно работало как USB MassStorage Device), один вызов nav_reset() приводит к инициализации встроенной Atmel File System.
Когда нужно остановить встроенную Atmel File System, или когда запускается режим устройства USB, нужно вызвать nav_exit(), чтобы сбросить (flush) содержимое кэша на диск. Ниже показан пример подпрограммы datalogging_task(), исходный код можно скачать по ссылке [3].
void datalogging_task(void)
{
// Изменение состояния сбора данных
if( Is_joy_down() // Если сбор данных запускается пользователем
&& (!Is_device_enumerated())) // и если неактивен режим устройства USB
{
if( !g_b_datalogging_running )
{
// Запуск сбора данных
nav_reset(); //** Инициализация File System
g_b_datalogging_running = datalogging_start();
}
}
if( Is_hwb() // если сбор данных остановлен пользователем
|| Is_device_enumerated() ) // или если запустился режим USB Device
{
if( g_b_datalogging_running )
{
// Остановка сбора данных
g_b_datalogging_running = FALSE;
datalogging_stop();
nav_exit(); //** Выход из модуля File System
}
}
// Выполнение фоновой задачи сбора данных
if( g_b_datalogging_running )
{
g_b_datalogging_running = datalogging_file_write_sector();
if( !g_b_datalogging_running )
{
datalogging_stop();
nav_exit(); //** Выход из модуля File System
}
}
}
5.2.2 Открытие диска (Open disk)
В этом примере нужен только один навигатор handle1, потому что в приложении есть только один просмотр диска, и в любой момент времени открыт только один файл. В этом случае мы выбрали навигатор по умолчанию, default navigator handle 0 (nav_select(0)).
Примечание: См. апноут AVR114 [2] для получения дополнительной информации по навигаторам (navigator handle).
Алгоритм для открытия диска зависит от количества подключенных дисков (см. конфигурацию в файле conf_access.h). По умолчанию пример кода использует DataFlash и драйвер MMC/SD. При этом используется следующий алгоритм:
Попытка смонтировать диск MMC/SD, и отформатировать его, если это необходимо
Если ошибка (диск отсутствует, неработоспособный, и т. п.)
Попытка смонтировать диск на носителе DataFlash, и отформатировать его, если это необходимо
Если ошибка (диск отсутствует, неработоспособный, и т. п.)
Прервать процесс сбора данных
Ниже приведен код подпрограммы datalogging_open_disk(), которая пытается открыть диск.
Bool datalogging_open_disk(void)
{
U8 u8_i;
nav_select(FS_NAV_ID_DEFAULT);
#if( (LUN_2 == ENABLE) && (LUN_3 == ENABLE)) // конфиг установлен в conf_access.h
// Выбрать и попытаться смонтировать диск MMC/SD (lun 1) или DataFlash (lun 0)
// Сначала надо попробовать MMC/SD
for( u8_i=1; u8_i!=0xFF; u8_i-- )
#else
// В этом месте только один вариант памяти, MMC/SD или DataFlash (lun 0)
for( u8_i=0; u8_i!=0xFF; u8_i-- )
#endif
{
if( nav_drive_set(u8_i) ) // Выбор драйвера (не диска)
{
// Драйвер доступен, смонтировать его
if( !nav_partition_mount() )
{
// Ошибка при монтировании, проверить статус ошибки
if( FS_ERR_NO_FORMAT != fs_g_status )
continue; // Ошибка диска (отсутствует, аппаратная ошибка,
// системная ошибка, и т. п.)
// Диск не отформатирован, отформатируем его
if( !nav_drive_format(FS_FORMAT_DEFAULT) )
continue; // Формат завершился неудачно
}
return TRUE; // В этом месте диск смонтирован
}
}
return FALSE; // Не найден работоспособный диск
}
5.2.3 Создание пути до файла (path)
Эта часть кода создает путь до файла наподобие Disk:\logxxx\logxxx.bin. Подпрограмма datalogging_create_path_file() создает каталог \logxxx\. Подпрограмма nav_setcwd() ищет и в конечном счете создает путь (третий аргумент должен быть TRUE). Ниже показан код подпрограммы datalogging_create_path_file(), которая создает путь.
Bool datalogging_create_path_file(void)
{
char ascii_name[15];
U16 u16_dir_num = 0;
if( !nav_dir_root() )
return FALSE; // Ошибка файловой системы
while( u16_dir_num < 30 ) // Это ограничение на количество директорий
// сделано здесь только для примера.
{
sprintf( ascii_name, "./log%03d/", u16_dir_num);
// Вход в подкаталог, и в конечном счете создание его, если
// такой подкаталог не существует
if( !nav_setcwd(ascii_name, FALSE, TRUE) )
return FALSE; // Ошибка файловой системы
// Создание файла
if( datalogging_create_file() )
return TRUE; // Файл создан
// В этом месте каталог заполнен, тогда делается переход
// в родительский каталог для создания там другого каталога.
if( !nav_dir_gotoparent() )
return FALSE; // Ошибка файловой системы
u16_dir_num++;
}
return FALSE; // Слишком много каталогов и файлов
}
Подпрограмма datalogging_create_file() создает файл \logxxx.bin. Здесь имеется ограничение на количество файлов лога в каталоге логов (до 10), потому что просмотр каталога с большим количеством файлов может работать довольно медленно.
Bool datalogging_create_file(void)
{
char ascii_name[15];
U16 u16_file_num = 0;
while( u16_file_num < 10 )
{
// Создание файла
sprintf(ascii_name, "log%03d.bin", u16_file_num);
if( nav_file_create(ascii_name) )
return TRUE; // Здесь файл создан, закрыт, и он пустой
// Ошибка при создании файла, нужно проверить код ошибки
if( fs_g_status != FS_ERR_FILE_EXIST )
return FALSE; // Ошибка файловой системы (диск переполнен,
// каталог переполнен, ...)
// Такой файл существует, увеличение числа в имени
u16_file_num++;
}
return FALSE; // Слишком много файлов в текущей директории
}
5.2.4 Выделение места под файл
Эта секция не обязательна для рассмотрения и использования, однако позволяет повысить быстродействие сбора данных (что полезно, когда нужно сохранять данные с высокой скоростью). Для получения подробностей, как это работает, см. раздел 6.5 апноута AVR114 [2].
Примечание: по окончании сбора данных остаток от выделенной памяти на носителе (размер выделенной памяти минус конечный размер файла) будет освобожден, когда файл закрывается. Ниже показан код подпрограммы datalogging_alloc_file_space(), которая выделяет место под файл на носителе данных.
Bool datalogging_alloc_file_space(void)
{
Fs_file_segment g_recorder_seg;
// Открыть файл, созданный в режиме записи
if( !file_open(FOPEN_MODE_W))
return FALSE;
// Задать размер сегмента для выделения (в единицах 512 байт)
// Примечание: Вы можете выделить место побольше в том случае,
// если не знаете общий размер файла.
g_recorder_seg.u16_size = FILE_ALLOC_SIZE;
// Выделение в FAT списка кластеров равного или меньшего
// в размере сегмента
if( !file_write(&g_recorder_seg) )
{
file_close();
return FALSE;
}
// Если хотите, то можете проверить минимальный выделенный размер.
if( g_recorder_seg.u16_size < FILE_ALLOC_SIZE_MIN )
{
file_close();
nav_file_del(FALSE);
return FALSE;
}
// Закрыть/открыть файл, чтобы обнулить его размер
// Примечание: это действие не удаляет предварительно созданное
// выделение в таблице FAT
file_close(); // закрытие файла
if( !file_open(FOPEN_MODE_W) ) // открытие файла в режиме записи, при
// этом принудительно обнуляется его размер
return FALSE;
return TRUE; //** Файл открыт и место в FAT выделено
}
5.2.5 Заполнение файла данными
Подпрограмма file_write_buf() является самой лучшей для заполнения файла. Использование размера буфера и текущей позиции записи, кратных 512 байтам, повысит скорость работы и даст оптимальное быстродействие, потому интерфейс с памятью использует блоки по 512 байт.
Буферы (2 * 512 байт) заполняются обработчиком прерывания timer0. Максимальная полоса пропускания для сохранения данных ATmega32U4 на частоте 8 МГц составляет 18 килобайт/сек. Это значение было измерено в следующем примере (подпрограмма datalogging_file_write_sector()).
Bool datalogging_file_write_sector(void)
{
// !!!! Внимание:
// Если размер записываемого буфера кратен 512 байтам,
// и если текущая позиция записи в файл тоже кратна 512
// байтам, то подпрограмма file_write_buf() будет работать
// очень эффективно.
if( g_b_buf_full[g_u8_cur_buf] )
{
if( !file_write_buf(&g_data_buf[g_u8_cur_buf*FS_SIZE_OF_SECTOR],
FS_SIZE_OF_SECTOR) )
return FALSE; // Ошибка записи
g_b_buf_full[g_u8_cur_buf] = FALSE;
// Теперь ждем нового буфера
g_u8_cur_buf++;
if( NB_DATA_BUF == g_u8_cur_buf )
g_u8_cur_buf = 0;
}
return TRUE;
}
[Ссылки]
1. AVR115: Data Logging with Atmel File System on ATmega32U4 site:atmel.com. 2. AVR114: использование файловой системы Atmel. 3. avr115.zip (проект EVK527-series4-datalogging, документация). 4. Atmel AVR JTAGICE mkII. 5. Программаторы для AVR. 6. Макетная плата AVR-USB32U4. |