STM32F411RE Nucleo USART LS20031 GPS Monitor

gps

The following program is a simple GPS monitor. Connect a GPS TX (output) to the Nucleo GPIO B6 pin and monitor the GPS output on your PC. The Nucleo connects to the PC via a Virtual COM port (Nucleo USART2). Remember to set appropriate baudrates between the GPS and Nucleo, and the Nucleo and PC.

Note: The program was compiled using the Keil uVision IDE and utilizes the low level serial routines (serial and retarget).

//usart gps test
#include "stdint.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_usart.h"
#include "serial.h"
 
//usart#2 virtual com port
//TX  GPIOA, GPIO_Pin_2
//usart#1 gps
//RX  GPIOB, GPIO_Pin_7
 
#define USART1_BUFFER_SIZE 32
//USART1 IRQ ring buffer
struct {
  uint8_t buffer[USART1_BUFFER_SIZE];
  int head;
  int tail;
  int size;
} U1RingBuffer;
 
void Push(uint8_t data) {
  int next;
 
  next = U1RingBuffer.head + 1;
  if (next >= U1RingBuffer.size)
    next = 0;
  //ring buffer is full
  if (next == U1RingBuffer.tail)
    return;
  U1RingBuffer.buffer[U1RingBuffer.head] = data;
  U1RingBuffer.head = next;
  return;
}
  
uint16_t Pop(void) {
  uint8_t data;
  int next;
 
  //if head isn't ahead of tail, we don't have any characters
  if (U1RingBuffer.head == U1RingBuffer.tail)
    return 0xffff;  //quit with error
  data = U1RingBuffer.buffer[U1RingBuffer.tail];
  next = U1RingBuffer.tail + 1;
  if (next >= U1RingBuffer.size)
    next = 0;
  U1RingBuffer.tail = next;
  return data;
}
 
//configure SystemCoreClock using HSI (HSE is not populated on Nucleo board)
void SystemCoreClockConfigure(void) {
  //enable HSI
  RCC->CR |= ((uint32_t)RCC_CR_HSION);                     
  //Wait for HSI Ready RCC->CFGR = RCC_CFGR_SW_HSI;
  while ((RCC->CR & RCC_CR_HSIRDY) == 0)
    ; 
  //wait for HSI used as system clock
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
    ;
  FLASH->ACR  = FLASH_ACR_PRFTEN;      //enable Prefetch Buffer
  FLASH->ACR |= FLASH_ACR_ICEN;        //instruction cache enable
  FLASH->ACR |= FLASH_ACR_DCEN;        //data cache enable
  FLASH->ACR |= FLASH_ACR_LATENCY_5WS; //flash 5 wait state
  RCC->CFGR |= RCC_CFGR_HPRE_DIV1;     //HCLK = SYSCLK
  RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;    //APB1 = HCLK/2
  RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;    //APB2 = HCLK/1
  RCC->CR &= ~RCC_CR_PLLON;            //disable PLL
  //PLL configuration: VCO=HSI/M*N, Sysclk=VCO/P
  //PLL_M=16, PLL_N=320, PLL_P=4, PLL_SRC=HSI, PLL_Q=8 for 80MHz SYSCLK/APB2, 40MHz APB1
  RCC->PLLCFGR = (16ul | (320ul<<6) | (1ul<<16) | (RCC_PLLCFGR_PLLSRC_HSI) | (8ul<<24));
  RCC->CR |= RCC_CR_PLLON;             //enable PLL
  //Wait till PLL is ready
  while((RCC->CR & RCC_CR_PLLRDY) == 0) 
    __NOP();
  //select PLL as system clock source
  RCC->CFGR &= ~RCC_CFGR_SW;                               
  RCC->CFGR |=  RCC_CFGR_SW_PLL;
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
    ; //wait till PLL is system clock src
}
 
void Usart1Init(void) {
  //gps: 57600baud, 8 data bits, no parity, 1 stop bits 
  RCC->AHB1ENR |= (1ul<<1);                 //enable GPIOB clock
  RCC->APB2ENR |= (1ul<<4);                 //enable usart1 peripheral clock

  //clear alt bits for gpiob pin #7
  GPIOB->AFR[7>>3] &= ~((uint32_t)15<<((uint32_t)((uint32_t)7&(uint32_t)7)*4));
  //set alt bits for pin #7
  GPIOB->AFR[7>>3] |= ((uint32_t)(GPIO_AF_USART1)<<((uint32_t)((uint32_t)7&(uint32_t)7)*4));
  //set GPIO_OType_PP, GPIO_PuPd_UP, GPIO_Speed_High, GPIO_AF_USART1
  GPIOB->MODER &= ~(3ul<<2*7);   //clear both mode bits
	//set alternate pin function
  GPIOB->MODER |= (GPIO_Mode_AF<<2*7);
  GPIOB->OTYPER &= ~(1ul<<7);    //clear (push/pull)
  GPIOB->OSPEEDR &= ~(3ul<<2*7); //clear both speed bits
	//set high speed
  GPIOB->OSPEEDR |= (GPIO_High_Speed<<2*7);
	//set pull up status
  GPIOB->PUPDR |= (GPIO_PuPd_UP<<2*7);

  //force reset, usart1 DeInit
  #define APB2Periph_USART1 ((uint32_t)0x00000010)
  RCC->APB2RSTR |= APB2Periph_USART1;  //enable
  RCC->APB2RSTR &= ~APB2Periph_USART1; //disable

  //set nvic irq priority
  NVIC->IP[USART1_IRQn] = 0x00;
  //enable selected IRQ channel
  NVIC->ISER[USART1_IRQn>>0x05] = (uint32_t)0x01<<(USART1_IRQn&(uint8_t)0x1F);
	
  //57600 baud @ 80MHz APB2 peripheral clock (PCLK1)
  USART1->BRR = (80000000ul/57600ul); 
  USART1->CR3 = 0x0000;                          //no flow control                 
  USART1->CR2 = 0x0000;                          //1 stop bit                      
  //enable RX, enable TX, enable interrupt
  USART1->CR1 = (USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE);
  //enable USART
  USART1->CR1 |= USART_CR1_UE;
}
 
void USART1_IRQHandler(void) {
  //check if interrupt was because data was received 
  if (USART1->SR&USART_SR_RXNE) 
    Push(USART1->DR);
}
 
void SER_OutString(char *s) {
  while (*s)
    SER_PutChar(*s++);
}   
 
void ConfigureNucleoGPIOs(void) {
  //configure nucleo blue button (pa13) pin as input, push-pull with pull-down 
  RCC->AHB1ENR |= (2ul<<1);                     //enable GPIOC clock
  GPIOC->MODER &= ~((3ul<<2*13));               //clear both mode bits
  GPIOC->MODER |= ((GPIO_Mode_IN<<2*13));       //set as input
  GPIOC->OTYPER &= ~((1ul<<13));                //clear (push/pull)
  GPIOC->OSPEEDR &= ~((3ul<<2*13));             //clear both speed bits
  GPIOC->OSPEEDR |= ((GPIO_High_Speed<<2*13));  //set high speed
  GPIOC->PUPDR |= (GPIO_PuPd_DOWN<<2*13);       //set pull down status
}
 
int main(void) {
  //configure HSI as System Clock
  SystemCoreClockConfigure();                              
  SystemCoreClockUpdate();
 
  //configure nucleo led and button pins
  ConfigureNucleoGPIOs();
   
  //configure USART1 ring buffer
  U1RingBuffer.size = USART1_BUFFER_SIZE;
  U1RingBuffer.head = 0;
  U1RingBuffer.tail = 0;
  //config usart1 for gps
  Usart1Init();
  //init for serial debug output
  SER_Initialize();
 
  //wait until button press
  while ((GPIOC->IDR & GPIO_Pin_13) != (uint32_t)Bit_RESET)
    ;
  SER_OutString("Hello World!\n");
 
  while(1) {
    if (U1RingBuffer.head != U1RingBuffer.tail) {
      uint16_t data;
 
      data = Pop();
      if ((data != 0xfff) && (data >= 0x20 && data <= 0x7e)) 
        SER_PutChar(data);
    }
  }
}
Advertisements

About Jim Eli

µC experimenter
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

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