Over 10 years we help companies reach their financial and branding goals. Engitech is a values-driven technology agency dedicated.

Gallery

Contacts

411 University St, Seattle, USA

engitech@oceanthemes.net

+1 -800-456-478-23

Getting Started and Peripheral Coding STM32 MCU's STM32F1

GPIO Peripheral in STM32F103 MCU

Table of Contents

GPIO Theory

So now  we’ll talk about GPIO pins . GPIO stands for general purpose input output pins; they are the means for communication between the microcontroller and the external world (using sensors etc).It is signal that arrives on these pins or a signal that is sent or written on these pins that facilitates this communication. These pins can be configured to act as input or output  via the application software(in our case stm32cube ide). The programmer can configure the pins as LOW or 0V or HIGH or 3.3V(or 5V ). 

These GPIO pins can also be configured to act as  special purpose pins as well where their alternate functionality is exploited . These alternate functionality includes UART , ADC , SPI etc . In the case of UART communication, Transmitter(Tx) and Receiver(Rx) pins are required. GPIO pins can be configured to act as TX or RX pins . Even in ADC the pins are configured to act as Analog pins having 12 bits of resolution . The alternate functions of various pins are shown below:

  • Input floating 

  • Input pull-up

  • Input pull-down

  • Analog

  • Output open-drain

  • Output push-pull

  • Alternate function push-pull

  • Alternate function open-drain

GPIO Peripheral in STM32F103

All the pins of STM32F103 are grouped in multiple ports as PORT A, PORT B, PORT C As can be seen from Pin configuration chart in the PA1 stands for Port A Pin 1. There are 37 GPIO pins in stm32f103 which are divided as PORT A with 16 pins, PORT B with 16 pins, PORT C with 3 pins and PORT D with 2 pins.

  • Each GPIO  port  has two 32-bit configuration registers (GPIOx_CRL, GPIOx_CRH), two 32-bit data registers (GPIOx_IDR, GPIOx_ODR), a 32-bit set/reset register (GPIOx_BSRR), a 16-bit reset register (GPIOx_BRR) and a 32-bit locking register (GPIOx_LCKR).
  • In the register names, x stands for the port to which pin belongs. If we are configuring pin PA1, it has Port A then registers would be accessed by GPIOA_CRL and etc.
  • Out of above-mentioned registers, GPIO peripheral has 2 most important registers:

GPIO Peripheral Block Diagram in STM32F103

  1. First after selecting the pin the port is decided
  2. Then after following the arrow the busses are selected based on it: APB/APB1 or AHB
  3. After which the clock is enabled to the particular port using either __HAL_RCC_GPIOX_CLK_ENABLE() function or using the RCC AHB1 peripheral clock enable register and selecting the port to which clock has to be provided by enabling it.

Methods to configure the GPIO Peripheral

Output configuration of the pin
Input configuration of the pin
Enter the label or the name of the pin
Configure the pin according to the various parameters
  • Configuring the busses i.e AHB1, AHB2, APB1, APB2 . The AHB bus is faster than APB bus and in case of certain modules they are connected to the same bus .Hence it depends upon the application which bus to use. As can be seen from the picture below the AHB1 takes clock to PORT A , PORT B , PORT C etc . Hence to initialize a pin to a particular port the in RCC AHB1 clock enable register GPIOEN is set to 1 (For Port A GPIOAEN , For Port B GPIOBEN etc)
  • Enabling the clock to that port otherwise the particular pin will not be functional
  •  Creating an instance of the structure and then using the members of the structure set the following:-
  1. PIN – Takes the pin no as input GPIO_PIN_X {where X -0 to 15} 
  2. MODE– Selects the mode the specified pin is supposed to work in . It takes in value Output Push Pull ,Output Open drain
  3. PULL- It selects the initial value of the pin and takes value no pull up no pull down, pull up or pull down
  4. SPEED- Selects the speed of the working of the specified pin i.e low, medium or high
  5. ALTERNATE- Specifies the alternate function performed by the pin UART TX OR RX , ADC etc,

GPIO Peripheral SDK using STM32HAL

We are going to use STM32 HAL SDK for using the GPIO peripheral of the STM32F103. STM32HAL is a very versatile and robust Software package for using Peripherals of the STM32 Microcontroller family. To know more about STM32HAL, refer to this link.

STM32 HAL Folder Structure

Each STM32 HAL has drivers for all the peripherals of the STM32 Microcontroller(One can navigate to the Driver folder in the STM32F1 HAL local repo installed). These drivers can be configured and enabled to use in the project via the STM32 CubeMX configuration tool, which is also integrated into STM32CubeIDE( just like told in the above section for configuring GPIO peripherals). Will be digging into that part, in the next section. For now, let’s understand the STM32HAL GPIO SDK for STM32F103 MCU.

  • stm32f1xx_hal_gpio.c: This file consists of various macros and  is responsible for the intialization and configuration of the functions which in turn configures the peripheral.
  • stm32f1xx_hal_gpio.h: consists of various structure definitions that help configure various parameters of the pin, enumeration, and various macros
  • stm32f1xx_ll_gpio.c & stm32f1xx_ll_gpio.h: GPIO Low-level driver source/header file, contains functions that configure the GPIO Peripheral registers at the hardware level. These files are the ones that actually interact with the hardware and make it configurable to our needs. 

STM32 HAL Functions for GPIO Peripheral

Functions are set of instructions that required to perform certain tasks. In general, a function is first declared in header file(.h) and then it is definied in source file(.c) and then called in main.c or application code.

It is of the form function return data type, function name and function arguments.

				
					// Basic introduction of functions in c
void func(int x);
int main()
{
func(x);
}
void func(int x)
{/*function body/*}
				
			

In Embedded functions are required to initialize a peripheral or configure it on the basis of various parameters which are passed on using arguments. This information is then passed on to the registers. 

List of functions used for GPIO HAL:

 

FUNCTION NAME 

  •   HAL_RCC_GPIOX_CLK_ENABLE()

FUNCTION DESCRIPTION

  This API is used to enable the clock to a particular port that will be delivered using AHB OR  APB busses. This function basically sets the APBENR bit in RCC register and after a delay enables the clock.

RETURN VALUE

              NONE

USAGE

				
					static void MX_GPIO_Init(void)
{
 

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
}
				
			

 FUNCTION NAME

  • void HAL_GPIO_Init (GPIO_TypeDef* GPIOx, GPIO_InitTypeDef *GPIO_Init)

 FUNCTION DESCRIPTION

This API takes 2 arguments as input that are pointer to structure GPIO_TypeDef* GPIOx this is usually used to specify the port (A,B etc) and GPIO_InitTypeDef *GPIO_Init which is basically the pointer to the structure GPIO_InitTypeDef this contains information of the pin configuration such as pin , mode , speed , pull , alternate.  This API basically initializes the specified pin according to configuration specified in GPIO_Init.

PARAMETERS (ARGUMENTS)

                           GPIOx:specifies the PORT ie X(A,B,C)

                           GPIO_Init: Pointer to GPIO_InitTypeDef that has the configuration information of the GPIO peripheral

RETURN VALUE

              NONE

USAGE

				
					static void MX_GPIO_Init(void){
 /*STEP 2*/
HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET); 
GPIO_InitStruct.Pin = led_Pin; 
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(led_GPIO_Port, &GPIO_InitStruct);
  }

				
			

 FUNCTION NAME

  • GPIO_PinState  HAL_GPIO_ReadPin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)

 FUNCTION DESCRIPTION

This API  is used to Read the value from a specified pin and it returns value of the type GPIO_PinState which is an enumeration in which GPIO_PIN _RESET has been assigned the value 0U and anything apart from this is GPIO_PIN_SET. This API takes in 2 arguments as input that are pointer to structure GPIO_TypeDef* GPIOx this is usually used to specify the port (A,B etc) and uint16_t GPIO_Pin this specifies the pin to be chosen and takes value from 0-15.

PARAMETERS (ARGUMENTS)

              GPIOx:specifies the PORT ie X(A,B,C) 

             GPIO_Pin:specifies the pin or the port bit to read from i.e from 0-15.

RETURN VALUE

             The input pin state value

USAGE

				
					uint8_t buttonval = 0;
  while (1)
  {
	buttonval=HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_PIN);
}
				
			

 FUNCTION NAME            

  • void HAL_GPIO_WritePin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)

  FUNCTION DESCRIPTION

This API is used to write either a HIGH or LOW at the specified pin . It takes in 3 arguments as input that are pointer to structure GPIO_TypeDef* GPIOx this is usually used to specify the port (A,B etc) , uint16_t GPIO_Pin this specifies the pin to be chosen and takes value from 0-15 and GPIO_PinState PinState which is an enum of the type GPIO_PinState which takes in value SET or RESET.

   PARAMETERS (ARGUMENTS)

              GPIOx:specifies the PORT ie X(A,B,C) 

              GPIO_Pin:specifies the pin or the port bit to read from i.e from 0-15.

               PinState:specifies the state to be written on the specified pin.These values are:

                            SET- To write a HIGH on the pin

                            RESET- To the clear or write LOW on the pin 

    RETURN VALUE

             NONE

USAGE

				
					while (1)
  {
    /* USER CODE END WHILE */
	  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET);
}
				
			

FUNCTION NAME

  • void HAL_GPIO_TogglePin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)

FUNCTION DESCRIPTION

This API is used to toggle or switch the state of the specified pin high to low or low to high. This API also takes in 2 arguments as input that are pointer to structure GPIO_TypeDef* GPIOx this is usually used to specify the port (A,B etc) and uint16_t GPIO_Pin this specifies the pin to be chosen and takes value from 0-15.

 PARAMETERS (ARGUMENTS)

              GPIOx:specifies the PORT ie X(A,B,C) 

              GPIO_Pin:specifies the pin or the port bit to read from i.e from 0-15.

 RETURN VALUE

             NONE

USAGE

				
					while (1)
  {
    /* USER CODE END WHILE */
	  HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET);
}
				
			

Data Types Involved

  • uint8_t
  • uint16_t
  • uint32_t
  • GPIO_InitTypeDef
  • GPIO_PinState
  1. uint8-t– This data type is used to store unsigned value of 8 bits which means that only positive or zero value can be stored in the data type .Ranging from 0-255. This data type can be used to store state of a pin in a variable
  2. uint16_t– This data type stores unsinged values of 16 bits . The range in this case is 0-65535.This data type can be used to define pins of a port as there are 16 pins in port A
  3. uint32_t-This data types stores unsigned values of 32 bits i.e it stores non-negative values in the range 0 to 4,294,967,295. This data type stores 4 bytes per element.
  4. GPIO_InitTypeDef- A structure that helps configure pin state such as:-
  • PIN-It defines the pin to be selected
  • MODE-It defines the mode the specified pin has to be set in such as input , output , alternate function and even in these modes push pull , open drain etc 
  • PULL- It sets the pin in 3 modes which are nopull , pull up , pull down
  • SPEED- It defines the speed or frequency  of the operation which can be low, medium , high

    5.GPIO_Pinstate- An enumerator that stores the pin state which can be SET or RESET

DEMO EXERCISE

1  CODE FOR BLINKING THE ON BOARD LED PC13 WITH A DELAY OF 1s

				
					MX_GPIO_Init();/*STEP 1*/
 while (1)
  {
    /* USER CODE END WHILE */
	  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET);/ *STEP 6*/
	  HAL_Delay(1000);/*STEP 7*/
	  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET); /*STEP 8*/
	  HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }
static void MX_GPIO_Init(void){
_HAL_RCC_GPIOC_CLK_ENABLE(); /*STEP 2*/
HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET); /*STEP 3*/
GPIO_InitStruct.Pin = led_Pin; /*STEP 4*/
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(led_GPIO_Port, &GPIO_InitStruct); /*STEP 5*/

				
			

STEPS INVOLVED

Create a function to configure all  the  pins involved in the application  . Configuration such as clock enable  ,  pin state initially, Pin no , mode, pull, speed. This function also involves HAL_GPIO_Init function that initializes the pin and has the information of its configurations.

Enable clock to the specified port in this case PORTC

Specify the initial state of the pin

 

Specify the pin no  ( used a label for the pin led_Pin)  the original pin no is 13 in this case. Also configure the pin mode which takes value output push pull or output open drain. Next configure the pull method which takes value no pull up  and no pull down in our case.Configure the speed of the peripheral according to requirement in this case we are choosing low frequency . 

 

Create the function specifying the port and all the information about the pin configuration

Write value to the pin as SET or HIGH 

Include a delay in our case it is 1000ms or 1s using HAL_Delay() function

Write value to the pin as RESET or LOW . Since all this is in a while (1) loop the led will continue to blink


 

NOTE-The above exercise can also be performed by replacing the 2  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET),  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET) with the HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin) and since the HAL API is called in the while loop the led will blink forever in a loop.

2 TURNING THE LED ON OR OFF USING A PUSH BUTTON

				
					MX_GPIO_Init();/*STEP 1*/
uint8_t buttonval = 0;
  while (1)
  {
	buttonval=HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_PIN);/ *STEP 7*/
    /* USER CODE END WHILE */
    if(buttonval == 0){
    	HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET);/ *STEP 8*/

    }
    else{
    	HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET);/ *STEP 9*/
    }
    /* USER CODE BEGIN 3 */
  }


static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();/*STEP 2*/
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET);/*STEP 3*/

  /*Configure GPIO pin : led_Pin */
  GPIO_InitStruct.Pin = led_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(led_GPIO_Port, &GPIO_InitStruct);/*STEP 5*/

  /*Configure GPIO pin : BTN_Pin */
  GPIO_InitStruct.Pin = BTN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(BTN_GPIO_Port, &GPIO_InitStruct);/*STEP 6*/

}

				
			

STEPS INVOLVED

Create a function to configure all  the  pins involved in the application  . Configuration such as clock enable  ,  pin state initially, Pin no , mode, pull, speed. This function also involves HAL_GPIO_Init function that initializes the pin and has the information of its configurations 

Enable clock to the specified port in this case PORTC

Specify the initial state of the pin

Specify the pin no  ( used a label for the pin led_Pin)  the original pin no is 13 in this case. Also configure the pin mode which takes value output push pull or output open drain. Next configure the pull method which takes value no pull up  and no pull down in our case.Configure the speed of the peripheral according to requirement in this case we are choosing low frequency . 

Create the function specifying the port and all the information about the pin configuration(PORT C PIN 13)

Create the function specifying the port and all the information about the pin configuration(PORT A ,PIN 0)

Initialize a variable buttonval to read the state of the Pin PA0 using HAL api GPIO_ReadPin

Write value to the pin as SET or HIGH when the pin is pressed

Write value to the pin as RESET or LOW when the button is not pressed . Since all this is in a while (1) loop the led will continue to blink


 

Author

W25Q128JV SPI Flash Memory: Part3

Table of Contents So continuing with the blog series of, W25Q128 SPI based flash memory\’s , in the previous blogs W25Q128JV SPI Flash Memory: Part1 | gettobyte  W25Q128JV SPI Flash Memory: Part2 | gettobyte we have gone through the introduction and overview for W25Q128JV  flash memory\’s. From this blog we are going to start with the Application and Device driver development of W25Q128JV IC. The Driver which i am going to develop in this blog will be generic can be used with any MCU, by just replacing the SPI API\’s. This application driver will be generic and simple one which will be having API\’s to perform basic Operation on this chip. We will be creating the 2 files, header file and source file(.h &.c) for W25Q128JV Application driver. Header file(.h) will be having all the Macros, Typedefs, Enums, Structures  and function declarations. Source file(.c) will be having all the function definitions and local variables to be used in the driver. Header file (W25Q128JV.h) First thing that we are going to do is define the Object like Macro\’s for all the registers of W25Q128JV in the header file(.h) of W25Q128JV. Macros are widely used in Embedded Programming for referring the registers address with the acronym of the Register names, so that it is easy for developer/user to understand the code or using the API.  Like, above if we want to read the JEDECID of the chip, instead of writing 0x9F in the Application code we can pass the Macro JEDECID. (Though we are not going to use all the registers of W25Q128, as in this blog we are just going to make the driver for following features. The Application driver will be having API\’s for reading-writing the data, erasing the data, reading-writing of Status registers, reading JEDEC ID , chip erase and chip initialise.) /* * w25q128jv.h * * Created on: 15-Apr-2021 * Author: kunal */ #define WriteEnable 0x06 #define WriteDisable 0x04 #define Dummybyte 0xA5 #define ReadSR1 0x05 #define WriteSR1 0x01 #define ReadSR2 0x35 //0x35: 00110101 #define WriteSR2 0x31 #define ReadSR3 0x15 #define WriteSR3 0x11 #define Write_Enab_for_Vol_status_regist 0x50 #define ReadData 0x03 #define WriteData 0x02 #define ReadDataFast 0x0B #define JEDECID 0x9F #define UinqueID 0x4B #define SectErase4KB 0x20 #define SectErase32KB 0x52 #define SectErase64KB 0xD8 #define chiperase 0xC7 #define reset1 0x66 #define reset2 0x99 #define read_addr1 0x020000 #define read_addr2 0x030000 #define read_addr3 0x040000 #define BUSY_BIT 0x01 #define WRITE_ENABLE_LATCH 0x02 Next thing in Header file will be the function definitions that would be used for interacting with the W25Q128JV flash memory\’s. void W25_Reset (void); void WriteEnable_flash(); void W25_Read_Data(uint32_t addr, char block[], uint32_t sz); void W25_Write_Data(uint32_t addr, char block[], uint32_t sz); uint32_t W25_Read_ID(void); void W25_Ini(void); void erase_sector4KB(uint32_t addr); void erase_sector32KB(uint32_t addr); void erase_sector64KB(uint32_t addr); void chip_erase(); void Uinque_ID(uint8_t uinque[]); void WriteSR(uint8_t SR_address, uint8_t SR_data); uint8_t ReadSR(uint8_t SR_address); void WaitForWriteEnd(void); Apart from Object like Macro\’s and Function definition\’s their would be 2 additional function like Macro\’s. //For STM32 CUBEMX #define cs_set() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET) #define cs_reset() HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET) //For STM32 BareMetal #define cs_set() GPIOA->ODR |= GPIO_ODR_ODR4; #define cs_reset() GPIOA->ODR &= ~GPIO_ODR_ODR4; As we are going to interface the W25Q128JV via SPI peripheral to our MCU\’s, in which MCU would be the Master device and W25Q128JV would be slave device. And in SPI -> Chip Select/Chip Enable pin is used for selecting the slave. Thus these 2 Macro\’s would be used for selecting the slave before the SPI instructions are send ( by using the cs_set()) and then deselecting the slave after the SPI instructions( by using the cs_reset()). Source file(W25q128JV.c) This file would be having all the function declarations of the functions which are defined in (W25Q128JV.h). The 2 most important API\’s which will Send and Receive the SPI commands are: void SPI1_Send (uint8_t *dt, uint16_t cnt) { HAL_SPI_Transmit (&hspi1, dt, cnt, 5000); } void SPI1_Recv (uint8_t *dt, uint16_t cnt) { HAL_SPI_Receive (&hspi1, dt, cnt, 5000); } API\’s Explained for Device Driver of W25Q128JV: void SPI1_Send () This function is wrapper for transmitting the data via SPI. not be used directly in Application driver, but it will always be called by Other API\’s of the driver to send the command to W25Q via SPI. It has 2 parameters: 1) uint8_t *dt –>pointer to store the data that will be transmitted from the Host MCU to W25Q128JV. 2) uint16_t cnt –> Variable that will be storing the size of data that has to be transmitted from MCU to W25Q128JV. void SPI1_Send (uint8_t *dt, uint16_t cnt) { HAL_SPI_Transmit (&hspi1, dt, cnt, 5000); } void SPI1_Recv() This function is wrapper for receiving the data via SPI. This API is also not used directly by the Application Driver, but will be used by the other API\’s of the driver for receivng the data from W25Q via SPI. It also has 2 parameters: uint8_t *dt –> pointer to store the data that will be received from the W25Q128JV. uint16_t cnt –> variable that will be storing the size of data that has to be received. void SPI1_Recv (uint8_t *dt, uint16_t cnt) { HAL_SPI_Receive (&hspi1, dt, cnt, 5000); } void W25_Reset(): W25Q SPI flash Ic\’s come in small package and they have limited number of the pins. Thus W25Q provides the software reset instruction feature. User/Developer can reset the W25Q by sending the specified instructions to W25Q  via SPI. After reset the device will come to its default state and loose all volatile content. Enable reset – 0x66( reset 1 macro) and Reset – 0x99( reset 2 macro)are the instructions that has to be send for generating the software reset. These 2 instructions has to be send in sequence, as any other command after the Enable reset command( 0x66) apart from Reset(0x99) will disable the reset procedure. Once the reset command is accepted it woulfd take approx 30us to reset the W25Q IC. void W25_Reset (void) { cs_reset(); tx_buf[0] = reset1; tx_buf[1] = reset2; SPI1_Send(tx_buf, 2); cs_set(); } void WriteEnable_flash(): In W25Q, before writing to any Page, Erasing any sector/block or performing full chip erase. We have to send the Write enable Instruction via SPI.

Read More »
Kunal Gupta
Author: Kunal Gupta

Author

Kunal Gupta

Leave a comment

Stay Updated With Us

Error: Contact form not found.

      Blog