5
\$\begingroup\$

I'm programming a STM32F407VG chip on the STM32F4Discovery board using CooCox CoIDE. I've stitched together a program based on some examples and tutorials I found online to get USART1 through pins PB6 and PB7, and USB-serial through the microusb port. I can get both working independently, but when I put them together, the USART doesn't work properly and sometimes spews out garbage. It seems that initializing the system clock changed my USART baudrate of 9600, but I'm not sure how to fix it.

Here is my code:

#define HSE_VALUE ((uint32_t)8000000) /* STM32 discovery uses a 8Mhz external crystal     */

#include <stdio.h>
#include "misc.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_conf.h"
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_exti.h"

#include "usbd_cdc_core.h"
#include "usbd_usr.h"
#include "usbd_desc.h"
#include "usbd_cdc_vcp.h"
#include "usb_dcd_int.h"

#define MAX_STRLEN 12 // max string length in characters
volatile char received_string[MAX_STRLEN+1];
volatile uint32_t ticker, downTicker;

/*
 * The USB data must be 4 byte aligned if DMA is enabled. This macro handles
 * the alignment, if necessary (it's actually magic, but don't tell anyone).
 */
__ALIGN_BEGIN USB_OTG_CORE_HANDLE  USB_OTG_dev __ALIGN_END;

// This funcion initializes the USART1 peripheral
void init_USART1(uint32_t baudrate){

    GPIO_InitTypeDef GPIO_InitStruct;                       // this is for the GPIO pins used as TX and RX
    USART_InitTypeDef USART_InitStruct;                     // this is for the USART1 initilization
    NVIC_InitTypeDef NVIC_InitStructure;                    // this is used to configure the NVIC (nested vector interrupt controller)

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  // Peripheral clock for USART1 (APB2) --> other USART uses APB1
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);   // Peripheral clock for GPIOB (PB6 = TX, PB7 = RX)

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;     // Pins 6 (TX) and 7 (RX) are used
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;               // the pins are configured as alternate function so the USART peripheral has access to them
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;          // this defines the IO speed and has nothing to do with the baudrate!
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;             // this defines the output type as push pull mode (as opposed to open drain)
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;               // this activates the pullup resistors on the IO pins
    GPIO_Init(GPIOB, &GPIO_InitStruct);                     // now all the values are passed to the GPIO_Init() function which sets the GPIO registers

    /* The RX and TX pins are now connected to their AF
     * so that the USART1 can take over control of the
     * pins
     */
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

    /* Now the USART_InitStruct is used to define the
     * properties of USART1
     */
    USART_InitStruct.USART_BaudRate = baudrate;             // the baudrate is set to the value we passed into this init function
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;// we want the data frame size to be 8 bits (standard)
    USART_InitStruct.USART_StopBits = USART_StopBits_1;     // we want 1 stop bit (standard)
    USART_InitStruct.USART_Parity = USART_Parity_No;        // we don't want a parity bit (standard)
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // we want to enable the transmitter and the receiver
    USART_Init(USART1, &USART_InitStruct);                  // again all the properties are passed to the USART_Init function which takes care of all the bit setting

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);          // enable the USART1 receive interrupt

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;       // we want to configure the USART1 interrupts
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;      // this sets the subpriority inside the group
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         // the USART1 interrupts are globally enabled
    NVIC_Init(&NVIC_InitStructure);                         // the properties are passed to the NVIC_Init function which takes care of the low level stuff

    USART_Cmd(USART1, ENABLE);                              // This enables the complete USART1 peripheral
}

/* This function is used to transmit a string of characters via
 * the USART specified in USARTx.
 *
 * It takes two arguments: USARTx --> can be any of the USARTs e.g. USART1, USART2 etc.
 *                         (volatile) char *s is the string you want to send
 *
 * Note: The string has to be passed to the function as a pointer because
 *       the compiler doesn't know the 'string' data type. In standard
 *       C a string is just an array of characters
 *
 * Note 2: At the moment it takes a volatile char because the received_string variable
 *         declared as volatile char --> otherwise the compiler will spit out warnings
 * */
void USART_puts(USART_TypeDef* USARTx, volatile char *s){

    while(*s){
        // wait until data register is empty
        while( !(USARTx->SR & 0x00000040) );
        USART_SendData(USARTx, *s);
        *s++;
    }
}

/* Initialize USB, IO, SysTick, and all those other things you do in the morning */
void init()
{
    /* Set up the system clocks */
    SystemInit();

    /* Setup SysTick or CROD! */
    SysTick_Config(SystemCoreClock / 1000);


    /* Setup USB */
    USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_CDC_cb, &USR_cb);

    /* Set up USART */
    init_USART1(9600);

}

/* Main function */
int main(void)
{

    init();

    while (1)
    {
        uint8_t theByte;
        if (VCP_get_char(&theByte))
        {
            VCP_put_char(theByte);
        }
    }

    return 0;
}

// Interrupt Handlers

void SysTick_Handler(void)
{
    ticker++;
    if (downTicker > 0)
    {
        downTicker--;
    }
}

void OTG_FS_IRQHandler(void)
{
  USBD_OTG_ISR_Handler (&USB_OTG_dev);
}

void OTG_FS_WKUP_IRQHandler(void)
{
  if(USB_OTG_dev.cfg.low_power)
  {
    *(uint32_t *)(0xE000ED10) &= 0xFFFFFFF9 ;
    SystemInit();
    USB_OTG_UngateClock(&USB_OTG_dev);
  }
  EXTI_ClearITPendingBit(EXTI_Line18);
}

// this is the interrupt request handler (IRQ) for ALL USART1 interrupts
void USART1_IRQHandler(void){

    // check if the USART1 receive interrupt flag was set
    if( USART_GetITStatus(USART1, USART_IT_RXNE) ){

        static uint8_t cnt = 0; // this counter is used to determine the string length
        char t = USART1->DR; // the character from the USART1 data register is saved in t

        if( (t != '\n') && (cnt < MAX_STRLEN) ){
            received_string[cnt] = t;
            cnt++;
        }
        else{ // otherwise reset the character counter and print the received string
            cnt = 0;
            USART_puts(USART1, received_string);
            //USART_puts(USART1, "\n");
            //memset(received_string, 0, MAX_STRLEN+1);
        }
    }
}

Here is the USART example: http://eliaselectronics.com/stm32f4-tutorials/stm32f4-usart-tutorial/

and here is the USB example: https://github.com/xenovacivus/STM32DiscoveryVCP/blob/master/main.c

\$\endgroup\$
11
\$\begingroup\$

Turns out the HSE value in the stm32f4xx.h file was set as 25000000 as default. I went in and editted the value to 8000000 and it works now.

So go into cmsis_boot > stm32f4xx.h > line 92:

Change from

#define HSE_VALUE ((uint32_t)25000000)

to

#define HSE_VALUE ((uint32_t)8000000)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.