Categories
Examples

STM32F4 Discovery Board ADC + Usart

In this post we are going to read ADC1 channel 10 on GPIO PC0 on STM32F4 Discovery board. First of all we will set the Clock PLL to run the discovery board on full speed with 168Mhz frequency. Later we initialize the USART with the baudrate of 230400 Kbps and finally we initialize the ADC and read the ADC and convert that 12 bit value (which goes from 0 to 4096) to string and transmit this string to Serial Terminal followed by one line break and carriage return.

Here is the complete code for it.

#include "stm32f4xx.h"
#include <stdio.h>

/*************************************************
* timer 2 interrupt handler
*************************************************/
void TIM2_IRQHandler(void)
{
   

 // clear interrupt status
 if (TIM2->DIER & 0x01) {
  if (TIM2->SR & 0x01) {
   TIM2->SR &= ~(1U << 0);
  }
 }

    GPIOD->ODR ^= (1 << 13);

    
}




void delay(volatile uint32_t);
void uart_init(void);
void uart_tx(unsigned char x);
void init_ADC(void)
{
 RCC->AHB1ENR|=RCC_AHB1ENR_GPIOCEN; //GPIOC clock enable
 GPIOC->MODER|=(3u<<(2*0)); //ADC input pin is analogue mode 
 RCC->APB2ENR|=RCC_APB2ENR_ADC1EN;  //ADC clock enable
 ADC1->SQR1&=~ADC_SQR1_L;      //set number of conversions per sequence to 1
 ADC1->SQR3&=~ADC_SQR3_SQ1;     //clear channel select bits
 ADC1->SQR3|=10;      //set channel
 ADC1->CR1 &= ~ADC_CR1_SCAN; //SCAN mode disabled 
 ADC1->CR2 &= ~ADC_CR2_CONT; //Disable continuous conversion
 ADC1->SMPR1 |= ADC_SMPR1_SMP10;
 
 
 
 ADC1->CR2|=ADC_CR2_ADON;      //enable ADC 
}

unsigned short read_adc(void)
{
 ADC1->CR2|=ADC_CR2_SWSTART;    //start ADC conversion
 while((ADC1->SR&ADC_SR_EOC)==0){__NOP();} //wait for ADC conversion complete
 return ADC1->DR;         //return converted value
}

void TIM2_Configuration(void){
 // enable TIM2 clock (bit0)
    RCC->APB1ENR |= (1 << 0);
    TIM2->PSC = 1749; //FOR DISCOVERY
  //TIM2->PSC = 1874; //FOR NECLUEO

    TIM2->ARR = 10000;

    // Update Interrupt Enable
    TIM2->DIER |= (1 << 0);

    // enable TIM2 IRQ from NVIC
    NVIC_EnableIRQ(TIM2_IRQn);

    // Enable Timer 2 module (CEN, bit0)
    TIM2->CR1 |= (1 << 0);
 
 
}

int main(void)
{ 
 
   RCC->APB1ENR |= RCC_APB1ENR_PWREN; //enable power interface clock source
    PWR->CR |= PWR_CR_VOS;

 
  #define PLL_N 168   //SYSTEM CLOCK SPEED (FCY (MHz))
  #define PLL_N 180   //SYSTEM CLOCK SPEED (FCY (MHz))
  #define HSI  16000000 //INTERAL OSC FREQUENCY
  
  #define PLL_M (HSI/2000000)  //Fcy = Fxtal x PLL_N/(PLL_P x PLL_M)
  #define PLL_P 2
  #define PLL_Q 7
    // HCLK = SYSCLK / 1
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;  //CORE CLOCK = 180MHZ
    
    // PCLK2 = HCLK / 2
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV4;  //PERIPHERAL CLOCK 2 = 180MHZ/4 = 45MHZ, THIS IS BECAUSE THE SPI MODULES (AND POSSIBLY OTHERS) DO NOT OPERATE PROPERLY WHEN PCLK > 42MHZ
    
    // PCLK1 = HCLK / 4
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;  //PERIPHERAL CLOCK 1 = 180MHZ/4 = 45MHZ, THIS IS BECAUSE THE SPI MODULES (AND POSSIBLY OTHERS) DO NOT OPERATE PROPERLY WHEN PCLK > 42MHZ

    // Configure the main PLL
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24);

    // Enable the main PLL
    RCC->CR |= RCC_CR_PLLON;

    // Wait till the main PLL is ready
    while(!(RCC->CR & RCC_CR_PLLRDY));
   
    // Configure Flash prefetch, Instruction cache, Data cache and wait state
    FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;

    // Select the main PLL as system clock source
    RCC->CFGR &=~ RCC_CFGR_SW;
    RCC->CFGR |= RCC_CFGR_SW_PLL;

    // Wait till the main PLL is used as system clock source
    while ((RCC->CFGR & RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);          
 
 
 SystemCoreClockUpdate();
 RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
    /* Make Pin 12 output (MODER: bits 25:24) */
    // Each pin is represented with two bits on the MODER register
    // 00 - input
    // 01 - output
    // 10 - alternate function   
  GPIOD->MODER &= GPIO_MODER_MODER13;
  GPIOD->MODER |= GPIO_MODER_MODER13_0;
    GPIOD->ODR |= (1 << 13);  // Toggle LED
  
  
  
  
  uart_init();
  init_ADC();
  TIM2_Configuration();
  

    const uint8_t brand[] = "Hello world\n\r";


  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
    while(1)
    {
   char str[10]; 
   unsigned int volts = read_adc();   
     // GPIOD->ODR ^= (1 << 13);  // Toggle LED
   uart_tx(((volts/10000)%10)+48);
   uart_tx(((volts/1000)%10)+48);
   uart_tx(((volts/100)%10)+48);
   uart_tx(((volts/10)%10)+48);
   uart_tx(((volts)%10)+48);
   uart_tx('\r');
   uart_tx('\n');
    // slow down
            //
    delay(300);
        
    }
 }

// A simple and not accurate delay function
// that will change the speed based on the optimization settings
void delay(volatile uint32_t s)
{
 long i=0;
    for(s; s>0; s--){
   for(i=0;i<16800;i++){}
       __asm("NOP");
    }
}


void uart_init(void){   
  // enable USART2 clock, bit 17 on APB1ENR
    RCC->APB1ENR |= (1 << 17);

    // enable GPIOA clock, bit 0 on AHB1ENR
    RCC->AHB1ENR |= (1 << 0);

    // set pin modes as alternate mode 7 (pins 2 and 3)
    GPIOA->MODER &= 0xFFFFFF0F; // Reset bits 10-15 to clear old values
    GPIOA->MODER |= 0x000000A0; // Set pin 2/3 to alternate func. mode (0b10)

    // set pin modes as high speed
    GPIOA->OSPEEDR |= 0x000000A0; // Set pin 2/3 to high speed mode (0b10)

    // choose AF7 for USART2 in Alternate Function registers
    GPIOA->AFR[0] |= (0x7 << 8); // for pin 2
    GPIOA->AFR[0] |= (0x7 << 12); // for pin 3

    // usart2 word length M, bit 12
    //USART2->CR1 |= (0 << 12); // 0 - 1,8,n

    // usart2 parity control, bit 9
    //USART2->CR1 |= (0 << 9); // 0 - no parity

    // usart2 tx enable, TE bit 3
    USART2->CR1 |= (1 << 3);

    // usart2 rx enable, RE bit 2
    USART2->CR1 |= (1 << 2);

    // baud rate = fCK / (8 * (2 - OVER8) * USARTDIV)
    //   for fCK = 42 Mhz, baud = 115200, OVER8 = 0
    //   USARTDIV = 42Mhz / 115200 / 16
    //   = 22.7864 22.8125
    // we can also look at the table in RM0090
    //   for 42 Mhz PCLK, OVER8 = 0 and 115.2 KBps baud
    //   we need to program 22.8125
    // Fraction : 16*0.8125 = 13 (multiply fraction with 16)
    // Mantissa : 22
    // 12-bit mantissa and 4-bit fraction
  
  
  
  //==== 45Mhz / 230400 / 16 => 195.3125
  //==== 42Mhz / 230400 / 16 => 11.393229
   
  //------------ USART2->BRR |= (22 << 4);   //FOR 115200 BAUD RATE
   //------------ USART2->BRR |= 13;
  
  
  //--------@42Mhz------------------
  USART2->BRR |= (11 << 4);  //THIS IS FOR 230400 BAUD RATE
  USART2->BRR |= 6;
    
  //---- @45Mhz ----------------
  //USART2->BRR |= (12 << 4);
   //USART2->BRR |= 3;
    //-----------------------------
  
  // enable usart2 - UE, bit 13
    USART2->CR1 |= USART_CR1_UE;

 
}


void uart_tx(unsigned char x){
 
 USART2->DR = x;
  // wait for transmit complete
  while(!(USART2->SR & (1 << 6)));
 
}
Code language: PHP (php)

By Abdul Rehman

My name is Abdul Rehman and I love to do Reasearch in Embedded Systems, Artificial Intelligence, Computer Vision and Engineering related fields. With 10+ years of experience in Research and Development field in Embedded systems I touched lot of technologies including Web development, and Mobile Application development. Now with the help of Social Presence, I like to share my knowledge and to document everything I learned and still learning.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.