- This repository was created because the course
is so interestingsucks.
- STM32-Embedded-System-Lab
- Example of some labs
You have to download STM32CubeIDE First. Then, select board STM32F4DISCOVERY and select debugger as J-LINK (OR ST-Link).
Each TIM uses different clock source frequency according to the table provided below.
APB1 Domain | APB2 domain |
---|---|
TIM2 | TIM1 |
TIM3 | TIM8 |
TIM4 | TIM9 |
TIM5 | TIM10 |
TIM6 | TIM11 |
TIM7 | |
TIM12 | |
TIM13 | |
TIM14 |
LED | GPIOD_PD |
---|---|
Green (LD4) | PD12 |
Orange (LD3) | PD13 |
Red (LD5) | PD14 |
Blue (LD6) | PD15 |
Button | GPIOA_PA |
---|---|
User button (blue button) | PA0 |
x in GPIOx for A, B, C, D eg. "GPIOA", "GPIOD"
// Read pin
// HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_xx);
HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_12); // read from PD12
HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); // read from user button
// Write pin
// HAL_GPIO_WritePin(GPIOx, GPIO_PIN_xx, GPIO_PIN_SET/GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET); //turn on light
// Toggle on/off pin
// HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_xx);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12); // toggle pin 12
// Delay
// HAL_Delay(uint32_t Delay);
HAL_Delay(1000); // delay for 1000 millisecond or 1 second
Register | Responsibility |
---|---|
Port Mode Register (MODER) | configure the I/O direction mode (input/output/alternate/analog) |
Port Mode Register (MODER) | configure the I/O direction mode (input/output/alternate/analog) |
Output Type Register (TYPER) | configure the output type of the I/O port (push-pull/open-drain) |
Output Speed Register (OSPEEDR) | configure the I/O output speed (2/25/50/100 MHz) |
Pull-Up/Pull-Down Register (PUPDR) | configure the I/O pull-up or pull-down (no pull-up, pull-down/pull-up/pull-down) |
Input Data Register (IDR) | contain the input value of the corresponding I/O port |
Output Data Register (ODR) | can be read and written by software (ODR bits can be individually set and reset by writing to the BSRR) |
Bit Set/Reset Register (BSRR) | can be used for atomic bit set/reset |
Configuration Lock Register (LCKR) | used to lock the configuration of the port bits when a correct write sequence is applied to bit 16 |
Alternate Function Low Register (AFRL) | configure alternate function I/Os |
Alternate Function High Register (AFRH) | configure alternate function I/Os |
int state = 0;
int push = 0;
if (state == 0) {
...
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == HAL_OK && !push) {
push = 1;
}
if (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == HAL_OK && push) {
push = 0;
state = 1;
}
} else if (state == 1) {
...
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == HAL_OK && !push) {
push = 1;
}
if (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == HAL_OK && push) {
push = 0;
state = 0;
}
}
- Another way
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)){
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)) {
}
}
Universal Asynchronous Receiver and Transmitter
- Connectivity >> USART2 >> Mode (Asynchronous)
- Connect the wire from RX (UART) to TX (Board) and from TX (UART) to RX (Board)
- Connect the ET-MINI USE-TTL Board to Computer
- Open terminal (e.g. Tera Term)
- Download Tera Term
- Very fricking important: set serial port to 115200 in Tera Term
Receive and print char one by one to terminal:
// Private variable
UART_HandleTypeDef huart2; // program generated
// User code
while(1){
// User variable
char buffer[1];
if (HAL_UART_Receive(&huart2, buffer, sizeof(buffer), HAL_MAX_DELAY) == HAL_OK){
HAL_UART_Transmit(&huart2, buffer, sizeof(buffer), HAL_MAX_DELAY);
}
}
Print whole string at terminal:
// Private variable
UART_HandleTypeDef huart2; // program generated
// User variable
int myValue;
char buffer[20];
while(1){
// sprintf(char *, char format, arguments...)
sprintf(buffer, "%d \r\n", myValue);
HAL_UART_Transmit(&huart2, &buffer, strlen(buffer), HAL_MAX_DELAY); // Transmit
}
**for mac user
-
Connect UART
-
Type in terminal : ls /dev/tty.*
-
Look for /dev/tty.usbserialXXXXXX and copy
-
Type in terminal : screen /dev/tty.usbserialXXXXXX 115200
*115200 is baud rate of STM32F4
If terminal return busy
- type : screen -ls
- kill everything by type : screen -X -S "session" kill
- System Core >> GPIO >> GPIO tab >> PA0 >> External Interrupt Mode with your prefered edge trigger detection
- System Core >> GPIO >> NVIC tab >> Enable EXTI line0 interrupt
- System Core >> NVIC >> NVIC tab >> set EXTI line0 interrupt preemptive priority to higher value (Higher number means lower priotity)
- Note : if you can't change the priority value, change priority group to higher bits
// Write this function in your main.c
// External interrupt/event controller (EXTI)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
... // do something
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)); // Debounce
HAL_Delay(100);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
}
- TIMx >> Set up PWM >> (see PWM)
- TIMx >> Parameter Setting >> Set up parameter(see Timer)
- TIMx >> auto-reload preload >> Enable
- TIMx >> NVIC Settings >> Enable TIM3 Global Interrupt or System Core >> NVIC >> Enable TIMx Global Interrupt
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM2) HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);
if (htim->Instance == TIM3) HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
}
int main(void)
{
// Init()
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
while (1) { ... }
}
- Pinout View >> Choose LED channel (PD12 to PD14) >> Change it to TIM4_CHx
- TIM4 >> Set up PWM >> (see PWM)
- TIM4 >> Parameter Setting >> Set up parameter(see Timer)
- LED will blink in the frequency that you have set.
- TIMx->CNT - Clock Counter (For ioc: Clock Configuration >> APB1 Timer clocks)
- TIMx->PSC - Prescaler Value (For ioc: TIMx >> Parameter Setting >> Prescaler)
- TIMx->ARR - Period Value (For ioc: TIMx >> Parameter Setting >> Counter Period)
- TIMx->CCRx - PWM for Channel x (For ioc: TIMx >> Parameter Setting >> PWM Generation Channel x >> Pulse)
- Tips : If you set APB1 Timer clocks = 16 MHz, Prescaler = 15999, you will be able to set Counter Period and Pulse in millisec.
Pulse Width Modulation
- TIMx >> Clock Source >> Internal Clock
- TIMx >> Channelx >> PWM Generation CHx
// Private variable
TIM_HandleTypeDef htim4; // program generated
// Don't forget to write this start method
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
while (1) {
TIM4->CCR3 = myPulse; // If you want to change PWM
}
Analog to Digital Converter
- Select your prefered Pin (e.g. PC3, PC2) and set mode to ADCxIN_x (e.g. ADC1_IN13)
- Go to Analog >> ADCx >> check INx
// Private variable
ADC_HandleTypeDef hadc1; // program generated
int adcValue;
while (1) {
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK) {
adcValue = HAL_ADC_GetValue(&hadc1);
}
}
Serial Peripheral Interface Bus
- Connectivity >> SPI2
- For transmitter select
Transmit Only Master
- For receiver select
Receive Only Slave
- For transmitter select
- Connect
SCK
andMOSI
// Transmitter
HAL_SPI_Transmit(&hspi1, "a", 1, HAL_MAX_DELAY);
// Receiver
HAL_SPI_Receive(&hspi1, "a", 1, HAL_MAX_DELAY);
Inter-Integrated Circuit Bus
- Connectivity >> I2C1
- Select
I2C
- Select
- Connect
SLC
andSDA
- Set some
{address}
// Transmitter
HAL_I2C_Master_Transmit(&hi2c1, {address}, "a", 1, HAL_MAX_DELAY);
// Receiver
HAL_I2C_Slave_Receive(&hi2c1, {address}, "a", 1, HAL_MAX_DELAY);
Real Time Operating System
- Read through this link for additional infomation!
- Middleware >> FREERTOS >> Interface (CMSIS_1)
- Task and Queue >> Task >> Add
...
void StartDefaultTask(void const * argument);
...
int main(void)
{
...
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
osKernelStart();
...
while (1) { ... }
}
void StartDefaultTask(void const * argument)
{
/* USER CODE BEGIN */
/* USER CODE END */
}
- Config parameters >> software timer definitions >> USE_TIMERS (Enabled)
- Timers and Semaphores >> Timers >> Add
...
osTimerId myTimer01Handle;
void Callback01(void const * argument);
...
int main(void)
{
...
osTimerDef(myTimer01, Callback01);
myTimer01Handle = osTimerCreate(osTimer(myTimer01), osTimerPeriodic, NULL);
osTimerStart(myTimer01Handle, 25);
...
while (1) { ... }
}
void Callback01(void const * argument)
{
/* USER CODE BEGIN Callback01 */
/* USER CODE END Callback01 */
}
osSemaphoreWait(myBinarySem01Handle, 10000);
osSemaphoreRelease(myBinarySem01Handle);