Home > ARM, Контроллеры, freescale, WizFi > Работа с UART в контроллерах MC1322x от Freescale для настройки WizFi220

Работа с UART в контроллерах MC1322x от Freescale для настройки WizFi220

Всем привет! Сегодня я расскажу о программировании этого контроллера, который практически не распространён в рунете. А зря. Штука удобная. Основной его плюс в том, что он имеет встроенный модуль ZigBee, из всей внешней обвязки требующий подключения всего двух элементов – конденсатора и антенны.

Суть задачи была в том, чтобы заставить работать связку “MK – WizFi220”. О WizFi220 я уже писал ранее. Но тогда не было программирования. А вот теперь – будет.

В чём же заключаются основные вкусняшки Freescale’овского UART’а?

  • Независимые 32-байтные буферы FIFO на приём и передачу.
  • Широкий диапазон скоростей: от 1.2 КБода до 1843.2 КБода.
  • Программируемое аппаратное управление потоком.

Что нам понадобится:

1. Само устройство с MC1322x.
2. Программатор
3. IAR Embedded Workbench for ARM
4. Freescale Beekit

Все дальнейшие выкладки я буду производить для своего девайса. Если у вас другой – делайте по-другому (КЭП).

Первое, что нужно сделать – сгенерировать проект для контроллера, поскольку он нагружен огромным количеством различной периферии, которая вся должна быть настроена. Ребята из Freescale постарались и сделали такую штуку, которая называется BeeKit Wireless Connectivity Toolkit и позволяет сделать это за пару кликов мышью. Сделаем это!

Запустим Freescale Beekit. Далее File -> New Project. В левом поле Project types выбираем SMAC, а в правом – Generic Application. Нажимаем OK, а потом Next. В качестве контроллера выбираем MC13224. В моём случае, target board – USB Dongle. Далее отключаем и светодиоды (LEDs) и клавиатуру  (Keyboard) и отключаем UART через USB. На этом базовая конфигурация завершена.

Далее открываем меню Solution и там выбираем пункт Export and Open Solution in IAR EWB. Если всё прошло хорошо, то у вас открылся IAR с проектом.

Для начала обратимся в файл Application/Source/generic_app.c.
В этом файле и будет содержаться программа, которую мы напишем ниже. Сейчас нам более интересно содержимое процедуры Uart_Init (файл UartUtil.c). Как видно из названия, в ней содержится код для правильной инициализации uart-модулей, которых, кстати, два.

Код для настройки выглядит следующим образом:

  1. void Uart_Init(uint8_t *mUARTRxBuffer, uint16_t mUARTBufferSize)
  2. {
  3.   UartConfig_t pConfig;
  4.   UartCallbackFunctions_t pCallback;
  5.  #if gUart_PortDefault_d == UART_1
  6.   //initialize GPIOs for UART1 and UART2 
  7.   GpioUart1Init();
  8.   //configure the uart parameters 
  9.   pConfig.UartParity = gUartParityNone_c;
  10.   pConfig.UartStopBits = gUartStopBits1_c;
  11.   pConfig.UartBaudrate = gUartDefaultBaud_c;
  12.   pConfig.UartFlowControlEnabled = gUart1_EnableHWFlowControl_d;
  13.   pConfig.UartRTSActiveHigh = FALSE;
  14.   //mount the interrupts corresponding to UART driver
  15.   IntAssignHandler(gUart1Int_c, (IntHandlerFunc_t)UartIsr1);
  16.   ITC_SetPriority(gUart1Int_c, gItcNormalPriority_c);
  17.   //enable the interrupts corresponding to UART driver
  18.   ITC_EnableInterrupt(gUart1Int_c);
  19.   //initialize the uart
  20.   UartOpen(UART_1,gPlatformClock_c);
  21.   UartSetConfig(UART_1, &pConfig);
  22. #if gUart1_EnableHWFlowControl_d == TRUE
  23.    UartSetCTSThreshold(UART_1, gUart_RxFlowControlSkew_d);
  24. #endif
  25.   //configure the Uart Rx and Tx Threshold
  26.   UartSetTransmitterThreshold(UART_1, 5);
  27.   UartSetReceiverThreshold(UART_1, 5);
  28.   //set pCallback functions
  29.   pCallback.pfUartWriteCallback = UartEventWrite1;
  30.   pCallback.pfUartReadCallback = UartEventRead1;
  31.   UartSetCallbackFunctions(UART_1, &pCallback);
  32. #endif

Вот и весь код инициализации. Пройдемся по каждой строке.

  1.   UartConfig_t pConfig;
  2.   UartCallbackFunctions_t pCallback;

Здесь заводятся переменные, описывающие настройки uart и callback-функций. Это чем-то похоже на библиотеку CMSIS от STM.

  1.   GpioUart1Init();

Эта функция обеспечивает корректную настройку портов ввода-вывода для работы с uart.

  1.   pConfig.UartParity = gUartParityNone_c;
  2.   pConfig.UartStopBits = gUartStopBits1_c;
  3.   pConfig.UartBaudrate = gUartDefaultBaud_c;
  4.   pConfig.UartFlowControlEnabled = gUart1_EnableHWFlowControl_d;
  5.   pConfig.UartRTSActiveHigh = FALSE;

В этих 5-ти строчках заполняются поля структуры, отвечающей за параметры uart1. Соответсвенно, параметры таковы: четности нет, 1 стоп-бит, 115200бод (gUartDefaultBaud_c), контроля потока нет (gUart1_EnableHWFlowControl_d) и активный уровень на RTS – низкий. Мне в этом коде не нравятся строки 14 и 15, так как они неочевидны. Можно же было написать по – другому. Например, так:

  1. pConfig.UartBaudrate = (UartBaudRate_t) 115200;
  2. pConfig.UartFlowControlEnabled = FALSE;

Ну да ладно, идём дальше.

  1.   IntAssignHandler(gUart1Int_c, (IntHandlerFunc_t)UartIsr1);
  2.   ITC_SetPriority(gUart1Int_c, gItcNormalPriority_c);
  3.   //enable the interrupts corresponding to UART driver
  4.   ITC_EnableInterrupt(gUart1Int_c);

Здесь происходит подключение прерывания с нормальным приоритетом.

  1.   UartOpen(UART_1,gPlatformClock_c);
  2.   UartSetConfig(UART_1, &pConfig);

Здесь всё тривиально: в строке 26 открывается UART, а в строке 27 – применение настроек к порту.

  1.   UartSetTransmitterThreshold(UART_1, 5);
  2.   UartSetReceiverThreshold(UART_1, 5);

В этих двух строчках устанавливает порог срабатывания. Зачем это нужно? А я сейчас расскажу. Как я уже писал, в контроллере имеются два 32-байтных буфера. Когда мы хотим что-то послать по UART, то наши данные сначала кладутся в буфер. Как только количество данных в нём достигает порога срабатывания, то вызывается внутренне прерывание, которое и пишет байты из буфера на ногу TX.

  1.   pCallback.pfUartWriteCallback = UartEventWrite1;
  2.   pCallback.pfUartReadCallback = UartEventRead1;
  3.   UartSetCallbackFunctions(UART_1, &pCallback);

Здесь происходит установка коллбэков на приём и передачу. Их надо устанавливать обязательно, иначе нельзя будет ни послать ни принять символ.

На этом настройка UART’а завершена и мы можем приступать к настройке WizFi220.

В первую очередь объявим массив команд, которые будут посланы модулю Wi-Fi.

  1.   uint8_t* commands[] =  {
  2.                    "ATE0\r",
  3.                    "ATB=115200\r",
  4.                    "AT+WD\r",
  5.                    "AT+WM=2\r",
  6.                    "AT+WAUTH=0\r",
  7.                    "AT+NDHCP=0\r",
  8.                    "AT+NSET=192.168.55.1,255.255.255.0,192.168.55.1r\",
  9.                    "AT+WA=LimitedAP,,8,\r",
  10.                   "AT+NSTCP=2345r\r",
  11.                   "AT\r"
  12.                    };

Идём по командам:

  1. Отключаем эхо команд. По-умолчанию, если послать модулю какую-либо команду, ответ будет таким: <Команда><результат исполнения>. После применения этой команды, на выходе будет только результат исполнения.
  2. Команда ATB позволяет настроить uart внутри WizFi220. В данном случае мы устанавливаем скорость 115200 и не изменяем настройки пакетов данных (8 бит, 1 стоп, нет проверки четности).
  3. AT+WD вызывает отключение модуля от всех беспроводных сетей.
  4. AT+WM=2 – WizFi220 будет функционировать в режиме Limited AP, позволяя подключится к себе 3-4 клиентам.
  5. AT+WAUTH=0 – отсутсвие шифрования. Точка доступа будет открытой.
  6. AT+NDHCP=0 – отключаем DHCP.
  7. AT+NSET=… – устанавливаем параметры модуля. IP-адрес сервера, маску подсети и адрес шлюза.
  8. AT+WA=LimitedAP,,8, – установка имени сети и канала.
  9. AT+NSTCP=2345 – поднимаем TCP-сервер на порту 2345.
  10. AT – команда, которая всегда возвращает [OK]

Необходимо помнить, что каждая команда должна заканчиваться либо символом ‘\r’, либо ‘\n’. Приняв этот символ, модуль считает, что команда завершена и начинает её обработку.

Один интересный момент был обнаружен в процессе написания кода. Непонятно почему первая посылаемая команда в модуль всегда возвращала [ERROR]. Причём любая. Как оказалось, это было из-за того, что при инициализации модуля линия передачи просаживается в ноль, что воспринимается модулем как нуль-байт. Из-за этого и были проблемы. А решение простое – первый раз надо отсылать две команды и игнорировать ответ от первой.

Далее заведём массив длин сообщений.

  1. uint8_t commandsSize[] =   {5116,  811114820143};

Он нам необходим для функции записи массива в буфер.

Еще одна не менее важная команду вынесена в отдельную переменную специально для того, чтобы посылать её в первый раз дважды. 🙂

  1. uint8_t msg[5] = "ATV0\r";

Эта команда заставляет WizFi220 возвращать числовые результаты исполнения команды вместо текстовых результатов. То бишь на AT модуль вернет не [OK], а 0. А это проще для распознавания.

И еще заведем один большой массив для приёма. Назовём его эпично и выделим эпичный размер.

  1. uint8_t MEGABUFFER[10000];

Теперь нам необходимо немножко подправить код callback-функции, чтобы она приняла следующий вид:

  1. void UartEventRead2(UartReadCallbackArgs_t* args)
  2. {
  3.   uint8_t byte;
  4.   responseStarted = true;
  5.   while(UartGetByteFromRxBuffer(UART_2, &byte))
  6.   {
  7.     (MEGABUFFER[++currentResponseCounter]) = byte;
  8.   }
  9.   gu8SCIDataFlag = TRUE;
  10.   gu16SCINumOfBytes = args->UartNumberBytesReceived;
  11.   gu8SCIStatus = args->UartStatus;
  12. }

Тут всё тривиально. Как только мы входим в callback-функцию, не выходим из неё до тех пор, пока не опустошим буфер приёма. На этом подготовка закончена и мы можем написать код для посылки команд модулю.

  1. while ((CurrentCommand < commandsCounter) && (AllCommandsReturnedOK))
  2. {
  3.   //Очищаем программный буфер
  4.   for (int i = 0; i < currentResponseCounter; ++i)
  5.   {
  6.     response[i] = '';
  7.   }
  8.   //Увеличиваем счётчик команд
  9.   ++CurrentCommand;
  10.   //Шлём команду
  11.   UartWriteData(UART_2, commands[CurrentCommand], commandsSize[CurrentCommand]);
  12.   //Ждём прихода ответа
  13.   while (!responseStarted)
  14.   {
  15.     ;
  16.   }
  17.   //Задержка для приёма ответа через Callback
  18.   DelayMs(10);
  19.   //Проверка результата исполнения команды
  20.   if (!(response[currentResponseCounter-1] == (uint8_t)'0'))
  21.   {
  22.      AllCommandsReturnedOK = FALSE;
  23.   }
  24. //Конец цикла
  25. }

Вот и всё. Напоследок расскажу у некоторых интересных моментах, которые были выявлены в процессе разработки.

  1. В контроллере MC1322x есть 2 модуля UART. Так вот, они неспособны работать одновременно на скорости 921600. Происходят потери символов в длинных сообщениях. Как я думаю, это из-за того что между входом в прерывание и входом в callback проходит примерно 270 тактов, что по времени сопоставимо с приёмом одного символа из-за этого и потери.
  2. Как я уже писал выше, при инициализации UART’а происходит просаживание линии в ноль, что может восприниматься принимающим устройствов как нуль-байт и вызывать проблемы.
  3. Первоначально разработка шла следующим образом: на компьютере была установлена ОС Ubuntu Linux, а там была поднята виртуалка с WinXP на борту, откуда и велась разработка. И тоже происходили потери символов, правда uart работал один и скорость его была 115200. Из-за чего это происходило, мне неизвестно.

Вот так. 🙂

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: