×

Внимание

Форум находится в режиме только для чтения.

Знакомство с Nuvoton M486. Работа с GPIO, UART и внешними прерываниям

5 года 11 мес. назад - 5 года 4 мес. назад #6064 от UnclePetya
Компания Nuvoton не так давно представила новое семейство контроллеров на ядре ARM Cortex-M4 – M480 Series. Про один из них (M486), расположенный на плате NuMaker-PFM-486, и пойдет речь в данной статье.
Микроконтроллер Nuvoton M486 имеет следующие характеристики:
• Частота ядра до 192 МГц;
• 512 Кб Flash memory с нулевым временным ожиданием (zero-wait state);
• 160 Кб RAM, включая 32 Кб внешнего SPI Flash кэша;
• 16-тиканальный DMA контроллер;
• EBI с параллельным интерфейсом LCD;
• 6x UART, 2x LIN;
• 3x I2C;
• SPI Flash, Quad-SPI, 4x SPI;
• 4x I2S (192 кГц, 16 бит), I2S (192 кГц, 32 бит);
• 2x CAN 2.0
• 2x USB 2.0 OTG;
• 10/100 Мб/с Ethernet.
На самой плате расположились аудиокодек (NAU88L25) с входом для микрофона и выходом для наушников (Jack 3.5), внешняя SPI Flash, слот для microSD, 4 светодиода, 3 кнопки, USB 2.0 High-Speed OTG, USB 1.1 Full-Speed OTG, Ethernet и естественно программатор.
Внешне плата очень приятная (рис.1).
Рис. 1 – Внешний вид NuMaker-PFM-M487
Nuvoton любезно предоставляет BSP для Keil и IAR (yadi.sk/d/3rjBefce3W79VF). Проект выполним в среде Keil uVision 5 (тут кому как нравится, мне больше Keil). Проблем с тем, чтобы собрать проект возникнуть недолжно – пользуемся одним из предложенных шаблонов в папке \M480_BSP_CMSIS_V3.02.000\SampleCode\Template.
Как говорилось выше, на плате имеются три пользовательских светодиода: красный (LEDR), желтый (LEDY) и зелёный (LEDG). Поставим задачу следующим образом: с помощью кнопки SW2 будем управлять направлением переключения светодиодов (влево – вправо), создадим некий поток свечения светодиодов; кнопкой SW3 будем управлять скоростью этого потока. Ну и для некоторой отладки воспользуемся интерфейсом UART для связи с компьютером. Ниже в таблице наглядно показано что-где на плате находится. Открываем наш голый проект из папки Template. Сходу добавляем в папку Library gpio.c (это будет чертовcки полезно). Как это сделать? ПКМ по папке Library – Add Existing Files to Group ‘Library’… - В открывшемся окне находим искомый gpio.c (\M480_BSP_CMSIS\Library\StdDriver\src\) – Нажимаем Add.
В шаблоне уже любезно настроено тактирование от внешнего источника на 192 МГц и включен модуль UART0 (т.е. нам настраивать его уже не нужно). Можно просто пользоваться функцией printf и выводить в терминал все, что нам вздумается.
Начинаем настраивать наши кнопочки и светодиоды. Тут есть два пути – используя gpio.c (стандартную библиотеку от Nuvoton) или используя CMSIS (то есть напрямую с регистрами). В данном проекте попробуем и так, и так.
Начнем с диодов и начнем с CMSIS. Необходимо настроить контакты PH.0 – PH.2 как выходы и на этом, пожалуй, все. Далее просто будем включать их поочередно. Светодиоды и кнопки на плате разведены следующим образом: Таким образом при подаче единицы на ножки PH.0 – PH.2 мы выключаем светодиоды. Чтобы включить светодиод, на соответствующий контакт нужно подать ноль.
Теперь перейдем непосредственно к программированию. Открываем наш великий во всех смыслах Technical Reference Manual на контроллер M486JDAE. Находим главу 6.5 GPIO и внимательно все там читаем. Итак, выбираем режим для наших контактов в соответствующем регистре Px_MODE (у нас x = H). Нам нужен режим Push-pull Output mode (смотрим рисунок ниже). Для того, чтобы задать режим Push-pull Output для 0-ого контакта порта H необходимо, чтобы в регистре PH_MODE нулевой бит был равен 1 и первый бит был равен 0. Все наглядно видно из рисунка выше. Пишем:
/* Set LEDs pins as GPIO OUT Push-pull */
	PH->MODE &= ~(GPIO_MODE_MODE0_Msk | GPIO_MODE_MODE1_Msk | GPIO_MODE_MODE2_Msk);
        PH->MODE |= 1 << 0 | 1 << 2 | 1 << 4; //либо 0х15
Теперь посмотрим, как нам выдавать на выход единицу либо ноль. Обращаем внимание на регистр Px_DOUT
Здесь все просто: единица в бит регистра задает единицу на соответствующем контакте. Таким образом для того, чтобы один светодиод светил, а два других – нет, пишем:
PH->DOUT &= ~(GPIO_DOUT_DOUT0_Msk);
PH->DOUT |= GPIO_DOUT_DOUT1_Msk | GPIO_DOUT_DOUT2_Msk;
Переходим к кнопкам и прерываниям. Пока кнопка не нажата, на контакт приходит 1. При нажатии подтягиваем контакт к земле.
Здесь воспользуемся услугами библиотечных функций. Настраиваем наши кнопочки на вход, выбираем режим прерывания (по заднему фронту) и включаем глобальное прерывание:
/* Configure PC.10 (SW2) as Input and enable int. by falling edge trigger */
GPIO_SetMode (PC, BIT10, GPIO_MODE_INPUT);
GPIO_EnableInt (PC, 10, GPIO_INT_FALLING);
NVIC_EnableIRQ (GPC_IRQn);
/* Configure PC.9 (SW3) as Input and enable int. by falling edge trigger */
GPIO_SetMode (PC, BIT9, GPIO_MODE_INPUT);
GPIO_EnableInt (PC, 9, GPIO_INT_FALLING);
NVIC_EnableIRQ (GPC_IRQn);
Не забываем написать что-то в обработчике прерываний (как минимум снять флаг прерывания). В нашем случае при нажатии SW2 меняем направление, при нажатии SW3 – скорость. Также сообщим на компьютер о том, что изменение произошло:
void GPC_IRQHandler(void)
{
    /* To check if PF.11 interrupt occurred */
    if(GPIO_GET_INT_FLAG(PC, BIT9))
    {
        GPIO_CLR_INT_FLAG(PC, BIT9);
				if (s == 50){
					s = 500;
				}
				else {
					s = s - 50;
				}
        printf("Flow speed is changed.\n");
    }
		else if (GPIO_GET_INT_FLAG(PC, BIT10))
    {
        GPIO_CLR_INT_FLAG(PC, BIT10);
				if (a == LEFT){
					a = RIGHT;
				}
				else {
					a = LEFT;
				}	
        printf("Flow direction is changed.\n");
    }
    else
    {
        /* Un-expected interrupt. Just clear all PB interrupts */
        PC->INTSRC = PC->INTSRC;
        printf("Un-expected interrupts.\n");
    }
}
GPIO_GET_INT_FLAG(PC, BIT9)– этим проверяем произошло ли прерывание по данному контакту. GPIO_CLR_INT_FLAG(PC, BIT9) – этим сбрасываем флаг о прерывании. В случае незапланированного прерывание (т.е. если оно произошло не по нашим кнопкам) выводим сообщение об этом событие и сбрасываем все флаги данного порта вот так: PC->INTSRC = PC->INTSRC;
Полный код получившейся программы можно найти во вложении. Компилируем. Прошиваем. Открываем терминал и видим следующие сообщения при нажатии кнопок:
Время создания страницы: 0.056 секунд
Работает на Kunena форум