How can I use hardware timer with cmsis-rtos2? - stm32

I know very well how to setup timer with hal API in stm32cubemx but I'm new to keil-rtx and cubemx does not support it. I wanna have a timer with less than 1 ms interval.
I want to know how to use hardware timer with rtos2?
I'm using stm32f407 microcontroller.
I've already increased kernel tick frequency and configured RTOS timer but it's not a good solution.

Here's an example of using the timer on the STM32F407 microcontroller with a 1 millisecond period:
#include "stm32f4xx.h"
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
// Code to be executed every 1 millisecond
}
}
void TIM3_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 999;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(SystemCoreClock / 1000000) - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* TIM IT enable */
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
/* Enable the TIM3 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE);
}
int main(void)
{
/* TIM3 configuration */
TIM3_Config();
while (1)
{
// main loop code
}
}
This code sets up TIM3 as a timer with a 1 millisecond period. The interrupt service routine (ISR) TIM3_IRQHandler will be called every 1 millisecond and execute the code inside it.

You can use any timer you want.
Read the reference manual of your STM and you can program it bare metal or using STM-supplied libraries.

Related

Volatile variable is not updated in ISR in STM32F429 in Keil

I am struggling with getting the value from Timer interrupt in STM32F429. I am using Keil. The HAL I am using is not the one from CubeMX but it is old version library. Due to some reasons, I must continue to work in this library.
I have declared the counter value in interrupt as "volatile". But the value I get is rubbish or it is not increasing.
The timer 4 is set to run execute ISR as 1us.
To verify it, I have toggled GPIOA Pin 1. And it toggles at 1us interval. But I need to up count variable "time4_tick" and it is not increasing.
I put two delays of 1000 ms and 2000 ms between start and stop of Timer 4. The count is not updating properly. I declared the variable volatile to not optimize it but it didn't solve my problem. Looks like something unknown is going here.
My code is below. What could be the problem here.
/********** Timer 4 interrupt *******/
__IO uint64_t time4_tick = 0;
void Sys_Timer4(void) // 1us
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
TIM_Cmd(TIM4, DISABLE);
TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE); // Enable TIM3 Update interrupt
TIM_TimeBaseStructure.TIM_Period = 21-1; //
TIM_TimeBaseStructure.TIM_Prescaler = 4-1; // 21*4/84 MHz = 1 usec
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_SetCounter(TIM4,0);
TIM_Cmd(TIM4, ENABLE);
TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //Added this
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); // Enable TIM2 Update interrupt
// Enable the TIM4 Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
}
/********** Timer 4 IRQ Handler*******/
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
time4_tick++;
GPIO_ToggleBits(GPIOA, GPIO_Pin_1);
}
}
/********** Main program loop *******/
int main(void)
{
// Other initializations
while(1)
{
TIM_Cmd(TIM4, ENABLE);
Delay_ms(1000);
TIM_Cmd(TIM4, DISABLE);
dbgmsg("time4_tick 1: %d\n", time4_tick);
time4_tick = 0;
TIM_Cmd(TIM4, ENABLE);
Delay_ms(2000);
TIM_Cmd(TIM4, DISABLE);
dbgmsg("time4_tick 2: %d\n", time4_tick);
time4_tick = 0;
// Other tasks
}
}
time4_tick should have different values after delay of 1000 ms and 2000 ms but it is showing same value. What is the problem here ?
dbgmsg("time4_tick 1: %d\n", time4_tick);
time4_tick = 0;
You zero it every time. Delete this line, then check. If it does not update then it means that the interrupt handler was not invoked.

problem with using SPI with DMA on STM32F1

I have a problem with triggering NSS pin, when transmitting SPI with DMA.
I use a CubeMX to generate whole core of project.
Time before triggering NSS to low, and sending data(also between end of transmission, and NSS to high) is too long. How can i make this times shorter?
I tried to use
HAL_DMA_PollForTransfer(&hdma_spi1_tx, HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
for detecting end of SPI DMA transmission but once it worked, and later when i changed something in CubeIDE it completely stoped working whole program...
int dmabusy = 0;
while (1)
{
uint8_t testing[] = {5, 10, 15, 20, 25, 30};
//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
dmaBusy = 1;
GPIOB->BSRR = GPIO_BSRR_BS12;
HAL_SPI_Transmit_DMA(&hspi1, testing, 6);
while(dmaBusy == 1);
GPIOB->BSRR = GPIO_BSRR_BR12;
//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
for(int i=0; i<80000; i++){ // OPOZNIACZ START
asm("NOP");
} // OPOZNIACZ STOP
}
/* USER CODE END 3 */
}
void HAL_SPI_TxCpltCallback (SPI_HandleTypeDef * hspi){
dmaBusy=0;
}

STM32F4 SPI interrupts stop firing with FreeRTOS

I'm trying to make an SPI communication between a F410 MCU and a RPi using SPI.
I post below the code that currently works (without FreeRTOS usage):
main.c
volatile int tx_done = 0;
volatile int rx_done = 0;
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
tx_done = 1;
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
rx_done = 1;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI5_Init();
MX_USART2_UART_Init();
const uint8_t BUF_SIZE = 16 * sizeof(uint8_t);
uint8_t buf[16];
// For UART debug
uint8_t dbg_buffer[64];
while (1) {
memset(buf, 0, BUF_SIZE);
HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, BUF_SIZE);
while (rx_done == 0) {};
rx_done = 0;
sprintf((char*) dbg_buffer, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d]\r\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
buf[7], buf[8], buf[9], buf[10], buf[11], buf[12],
buf[13], buf[14], buf[15]);
HAL_UART_Transmit(&huart2, dbg_buffer, strlen((char const*) dbg_buffer), 50);
HAL_SPI_Transmit_IT(&hspi5, (uint8_t*) &buf, BUF_SIZE);
while (tx_done == 0) {};
tx_done = 0;
}
}
stm32f4xx_it.c
/**
* #brief This function handles TIM1 trigger and commutation interrupts and TIM11 global interrupt.
*/
void TIM1_TRG_COM_TIM11_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim11);
}
/**
* #brief This function handles SPI5 global interrupt.
*/
void SPI5_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi5);
}
spi.c
/* SPI5 init function */
void MX_SPI5_Init(void)
{
hspi5.Instance = SPI5;
hspi5.Init.Mode = SPI_MODE_SLAVE;
hspi5.Init.Direction = SPI_DIRECTION_2LINES;
hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi5.Init.NSS = SPI_NSS_HARD_INPUT;
hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi5.Init.CRCPolynomial = 15;
if (HAL_SPI_Init(&hspi5) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
[...]
HAL_NVIC_SetPriority(SPI5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI5_IRQn);
}
This working fine with my test code on the other (raspberry pi) side, sending a SPI frame every second, waiting 100ms and reading the answer from the F410.
Now, when I activate FreeRTOS, I move the while(1) loop content to a task, and creates it with
BaseType_t task1 = xTaskCreate(task_1, "task_1", 512, NULL, tskIDLE_PRIORITY, &xHandle);
and osKernelStart(). I also use the TIM11 as Timebase Source (under SYS tab on CubeMX as advised by the software itself)
Then I have the following behavior: If I place breakpoints inside both Tx/Rx SPI interrupt, I found that a couple (3-4 ?) of them are fired, then never again. If I stop my code I see I'm stucked in the
while (rx_done == 0) {};
loop, confirming that I don't get SPI RX interrupts anymore whereas there is still frame coming on the SPI bus.
To dig a little into that theory, I made another test with this in my task:
while(1) {
memset(buf, 0, 16);
HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, 16);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
// Wait for RX interrupt, task is suspended to give processing time to (incoming) others tasks
vTaskSuspend(NULL);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
and in my Rx interrupt, I simply call
xTaskResumeFromISR(task1Handle);
With this code, the first packet sent is read correctly by the STM32F4, and task print it on USART2 and suspend itself again. From then, (checked with a breakpoint inside), the Rx interrupt is never called again, so the task resume inside neither, and my code is frozen...
It really looks like there is a messing between FreeRTOS and STM32 HAL SPI/interrupt handling ?
Any help will be gladly accepted !
Do you call NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); as described in the red text on this page: https://www.freertos.org/RTOS-Cortex-M3-M4.html ?
If you are using an STM32 with the STM32 driver library then ensure all the priority bits are assigned to be preempt priority bits by calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.

STM32F4 PLL Precision

Im trying to configure clocks on STM32F4 Discovery for precise time measurement. I have this configuration:
int main(void)
{
NVIC_InitTypeDef nvici;
GPIO_InitTypeDef gpioi;
TIM_TimeBaseInitTypeDef timtbi;
SystemInit();
RCC_HSEConfig(RCC_HSE_ON);
RCC_PLLConfig(RCC_PLLCFGR_PLLSRC_HSE, 8, 320, 8, 8);
RCC_PLLCmd(ENABLE);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCK);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
nvici.NVIC_IRQChannel = TIM2_IRQn;
nvici.NVIC_IRQChannelPreemptionPriority = 0;
nvici.NVIC_IRQChannelSubPriority = 1;
nvici.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvici);
gpioi.GPIO_Pin = GPIO_Pin_15;
gpioi.GPIO_Mode = GPIO_Mode_OUT;
gpioi.GPIO_OType = GPIO_OType_PP;
gpioi.GPIO_Speed = GPIO_Speed_100MHz;
gpioi.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD,&gpioi);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
timtbi.TIM_Period = 20000000;
timtbi.TIM_Prescaler = 0;
timtbi.TIM_ClockDivision = 0;
timtbi.TIM_CounterMode = TIM_CounterMode_Up;
timtbi.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &timtbi);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
GPIO_SetBits(GPIOD,GPIO_Pin_15);
while(1)
{
}
}
void TIM2_IRQHandler()
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
GPIO_ToggleBits(GPIOD,GPIO_Pin_15);
}
with this i should have TIM2 sourced with 20MHz clock, but it appears to have diffrent frequency (about 10-30% diffrent). This problem appears for all other PLL configurations i tried, but when i use HSE as SYSCLK directly it works just fine. Am i doing something wrong, or is it PLL that isn't reliable?
Can't say with 100% certainty whether that's the problem, but after enabling the HSE using RCC_HSEConfig(), you should call RCC_WaitForHSEStartUp() since it takes a while for the HSE to start oscillating, and check the return code to make sure the call was successful and the HSE actually initialized.
Also, if you're using the system_stm32f4xx.c file that comes with the Standard Peripheral Library, you can scrap your PLL initialization code and just use the code that's called by SystemInit(). There are a few #defines that control the PLL configurations, near the beginning of the file (#define PLL_M, #define PLL_N and so on; their purpose should be self-evident). I always initialize my clocks using the code there, and they're always precise to within the crystal's accuracy. Note that this code assumes a 25 MHz oscillator by using PLL_M equal to 25, so you should set it to 8 for use with the STM32F4DISCOVERY board -- exactly as you've already done in your code. I'm not suggesting this because I have any prejudices against your code, but the code there has been tested far and wide, and in my experience it can be trusted.

How to configure the STM32103 for CAN and remapping the pins to PB8 and PB9

I am trying to, at this stage, simply send a transmission using CAN on the STM32F103 V8T6. The chip is implemented on a board that was customized by my company. Looking at the schematic I see that the CAN Tx and Rx pins were remapped to PB9 (Tx) and PB8 (Rx). All that being said, I have been able to use LoopBack mode successfully (using the latest example from STM "V3.5.0") but have have NOT been able to get Normal mode working. Can someone please let me know if they see an obvious flaw in my initial configuration?! I have included only the code related to configuration and left out the transmission function call.
int main (void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure CAN pin: RX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure CAN pin: TX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Remap2 is for PB8 and PB9
GPIO_PinRemapConfig(GPIO_Remap2_CAN1 , ENABLE);
}
Here is my transmit function
void CAN_TransmitMyMsg(void)
{
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CanTxMsg TxMessage;
uint32_t i = 0;
uint8_t TransmitMailbox = 0;
uint8_t status = 0;
/* CAN register init */
CAN_DeInit(CANx);
CAN_StructInit(&CAN_InitStructure);
/* CAN cell init */
CAN_InitStructure.CAN_TTCM=DISABLE;
CAN_InitStructure.CAN_ABOM=DISABLE;
CAN_InitStructure.CAN_AWUM=DISABLE;
CAN_InitStructure.CAN_NART=DISABLE;
CAN_InitStructure.CAN_RFLM=DISABLE;
CAN_InitStructure.CAN_TXFP=DISABLE;
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;
/* Baudrate = 125kbps*/
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1=CAN_BS1_2tq;
CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;
CAN_InitStructure.CAN_Prescaler=48;
CAN_Init(CANx, &CAN_InitStructure);
/* CAN filter init */
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
/* transmit */
TxMessage.StdId=0x11;
TxMessage.RTR=CAN_RTR_DATA;
TxMessage.IDE=CAN_ID_STD;
TxMessage.DLC=2;
TxMessage.Data[0]=0xCA;
TxMessage.Data[1]=0xFE;
TransmitMailbox=CAN_Transmit(CANx, &TxMessage);
//wait until CAN transmission is OK
i = 0;
while((status != CANTXOK) && (i != 0xFFFF))
{
status = CAN_TransmitStatus(CANx, TransmitMailbox);
i++;
}
}
This resource has been helpful, but ultimately insufficient.
STM32F103 microcontroller CAN messages
Thanks!
Daniel
I had similar problems. My problem was in bad selection of comm parameters (timequantums and prescaler)
I debug it in this way:
I checked, that RSS pin of CAN transceiver (I used MCP 2551 I/P)
I switched it to loopback and with osciloscope check output signal on TX channel and on CANH to CANL (if the output is configured properly)
I looked to RCC configuration - the prescaler of APB1 clock has been changed to 2 (I excepted 4)
For a successful transmission, the CAN controller expects an 'acknowledge' bit which is part of the CAN protocol. If your CAN monitor (by NI) is in listen mode, there will not be an acknowledge-bit(!), and thus you don't get an indication of a successfull transmission at the sending end.
GPIO_Remap2_CAN1 remaps the CAN1 peripheral to PD0 and PD1, not PB8 and PB9. You want GPIO_Remap1_CAN1.
STD peripheral library is deprecated, but since I couldn't find any better examples, I used your not working code as a base.
Initially, I had the same behavior that it worked only in loopback.
After removing remapping to pins PB8 and PB9 and setting high speed GPIO for TX pin it started working. Here are my GPIO settings for PA11 and PA12
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Configure CAN pin: RX */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure CAN pin: TX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = **GPIO_Speed_50MHz**;
GPIO_Init(GPIOA, &GPIO_InitStructure);
The rest I kept the same. (Except changing CANx to CAN1).