Další mini pokračování z předchozího článku o programování USARTu pro STM32L100 a jemu podobné typy (STM32F0, STM32F3, STM32F4…)
V tomto článku se znova podíváme na USART, tentokrát ale s přerušením. Budeme řešit jenom jeden, trochu větší problém a to zápis přerušení do NVIC (Nested vectored interrupt controller) a ISER (Interrupt Set Enable Register). Článek opět vychází ze stránek http://joudove.8u.cz/.
Zde přibyl pouze kousek kódu a to povolení přerušení od přijmu (receive).
Poté ještě povolíme přerušení v řadiči přerušení.
Tuto část vysvětlím. Každé přerušení má své číslo, toto číslo se musí zapsat do registru NVIC resp. ISER.
USART1 má číslo 37. To se nám ovšem do 32 bit registru nevejde. Proto je ISER rozdělen na ISER[0] a ISER[1]. V ISER[0] jsou přerušení od 0 do 31 a v ISER[1] od 32 do 56. Část seznamu přerušení vidíte níže.
/****** STM32L specific Interrupt Numbers ***********************************************************/
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */
TAMPER_STAMP_IRQn = 2, /*!< Tamper and Time Stamp through EXTI Line Interrupts */
RTC_WKUP_IRQn = 3, /*!< RTC Wakeup Timer through EXTI Line Interrupt */
FLASH_IRQn = 4, /*!< FLASH global Interrupt */
RCC_IRQn = 5, /*!< RCC global Interrupt */
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */
DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */
DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */
DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */
DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */
DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */
DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */
ADC1_IRQn = 18, /*!< ADC1 global Interrupt */
USB_HP_IRQn = 19, /*!< USB High Priority Interrupt */
USB_LP_IRQn = 20, /*!< USB Low Priority Interrupt */
DAC_IRQn = 21, /*!< DAC Interrupt */
COMP_IRQn = 22, /*!< Comparator through EXTI Line Interrupt */
EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
LCD_IRQn = 24, /*!< LCD Interrupt */
TIM9_IRQn = 25, /*!< TIM9 global Interrupt */
TIM10_IRQn = 26, /*!< TIM10 global Interrupt */
TIM11_IRQn = 27, /*!< TIM11 global Interrupt */
TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
TIM4_IRQn = 30, /*!< TIM4 global Interrupt */
I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */
I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */
I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */
SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
SPI2_IRQn = 36, /*!< SPI2 global Interrupt */
USART1_IRQn = 37, /*!< USART1 global Interrupt */
USART2_IRQn = 38, /*!< USART2 global Interrupt */
USART3_IRQn = 39, /*!< USART3 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTC_Alarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
USB_FS_WKUP_IRQn = 42, /*!< USB FS WakeUp from suspend through EXTI Line Interrupt */
TIM6_IRQn = 43, /*!< TIM6 global Interrupt */
Kompletní seznam najdete v stm32l1xx.h.
A zpět k předešlému zápisu. Ten upravený vychází ze zápisu:
NVIC->ISER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* enable interrupt */
Pro zakázaní přerušení je použit zápis:
NVIC->ICER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); /* disable interrupt */
Předchozí část kódu byl zkrácený zápis tohoto. Jinak ho můžete také zapsat takto:
NVIC->ISER[1] |= (1 << (USART1_IRQn & 0x1F))
Což ve zkratce znamená, že s hodnotou USART1_IRQn = 37 provedeme bitový součin (&) s hodnotou 0x1F (31) což ve výsledku dá hodnotu 5. Po bitovém posunu o 5 se povolí přerušení od USART1.
Na závěr přikládám zdrojové kódy:
MAIN.C
/* Includes */
#include
#include
#include „stm32l1xx.h“
#include „stm32l1xx_conf.h“
/**
**===========================================================================
** http://chiptron.cz
** Abstract: main program
** APB2 bezi na 16MHz !!!
**
**===========================================================================
*/
int main(void)
{
//—-LED—-//
RCC->AHBENR |= RCC_AHBENR_GPIOCEN; //Povoleni clocku pro port C
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOCRST; //reset GPIOC
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOCRST;
GPIOC->MODER |= GPIO_MODER_MODER9_0 | GPIO_MODER_MODER8_0; //Nastaveni pinu 9 a 8 na portu C
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR9 | GPIO_OSPEEDER_OSPEEDR8; // Nastaveni rychlosti pro port C PIN 9 a PIN 8
GPIOC->ODR = GPIO_ODR_ODR_9 | GPIO_ODR_ODR_8; //Zapis do vystupniho registru portu E PIN 9 a PIN 8
//—PIN pro USART1—//
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; //povoleni clocku pro GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; //reset GPIOA
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST;
GPIOA->MODER |= (GPIO_MODER_MODER9_1 | GPIO_MODER_MODER10_1); //alternativni fuknce PIN 9 a 10
GPIOA->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR9_1 | GPIO_OSPEEDER_OSPEEDR10_1); //rychlost 50MHz
GPIOA->AFR[1] |= 0x00000770; //nastaveni alternativnich funkci
//—USART1—//
RCC->APB2ENR |= (RCC_APB2ENR_USART1EN); //povoleni clocku USART1
RCC->APB2RSTR |= RCC_APB2RSTR_USART1RST; //reset USART1
RCC->APB2RSTR &= ~RCC_APB2RSTR_USART1RST;
USART1->CR1 = (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE); //povoleni USART1, prijem, vysilani, interrupt
USART1->CR2 = 0x0000;
USART1->CR3 = 0x0000;
USART1->BRR = 0x682; //APB2 bezi na 16MHz!!! mantisa – 104dec, fraction 2.56dec
NVIC->ISER[1] |= (1 << 5);
GPIOC->ODR &= ~(GPIO_ODR_ODR_9 | GPIO_ODR_ODR_8);
while (1);
}
Do STM32L1xx_it.c někam přidáme obsluhu přerušení:
void USART1_IRQHandler(void){
uint8_t znak;
if((USART1->SR & USART_SR_RXNE) && !(USART1->SR & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE))) //pokud se nenahodi flagy
{
znak = USART1->DR; // do promene znak zapis z registru DR
GPIOC->ODR ^= GPIO_ODR_ODR_9; //neguj LED
USART1->DR = znak;
}
}