STM32 odd timer1 behavior in Master-Slave Configuration - mb code issue - c

I'm currently working on an embedded system which is meant to output a specific pulse sequence at equidistant timings. Therefore, I use the STM32 - DISCO board with the FreeRTOS kernel, as a first test.
I configured TIM3 as Master triggering TIM1. TIM1 is triggered with a frequency of 1Hz or every second. TIM3 then generates a pulse sequence on it's output.
I configured the TIM3 output to PB4, and TIM1 to PA9. This configuration works as expected, but now I wanted to change the configuration on the fly with a structure that stores my settings and can be passed as pointer to a function that configures both timers.
As a first step, I generated a data structure and initialized it in my timer function to configure TIM3.
PG_ERR TIM_Master_Init(void){
PG_HandleTypeDef hPG_timer;
hPG_timer.PLS.Prescaler = 139;
hPG_timer.PLS.Period = 60000;
hPG_timer.PLS.DutyCycle = 30000;
hPG_timer.PLS.RepetitionCounter = 5;
hPG_timer.PLS.PercentChange = 0;
/* Timer3 handler declaration: Master */
TIM_HandleTypeDef TimMasterHandle;
/* Master configuration structure */
TIM_MasterConfigTypeDef sMasterConfig;
/* Output compare structure */
TIM_OC_InitTypeDef sOCConfig;
__TIM3_CLK_ENABLE();
PG_ERR xPGERR = PG_ERR_NONE;
/* Compute the prescaler value to have TIM3 counter clock equal to 60 KHz */
/* Set TIMx instance */
TimMasterHandle.Instance = MASTER_TIM;
/* Master configuration: TIM3 */
TimMasterHandle.Init.Period = 60000 - 1;
TimMasterHandle.Init.Prescaler = 1399;
TimMasterHandle.Init.ClockDivision = 0;
TimMasterHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
if (HAL_TIM_PWM_Init(&TimMasterHandle) != HAL_OK){
xPGERR = PG_ERR_TIM;
}
/* Configure the PWM_channel_1 */
sOCConfig.OCMode = TIM_OCMODE_PWM1;
sOCConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
sOCConfig.OCFastMode = TIM_OCFAST_ENABLE;
sOCConfig.Pulse = 30000;
if (HAL_TIM_PWM_ConfigChannel(&TimMasterHandle, &sOCConfig, TIM_CHANNEL_1) != HAL_OK){
xPGERR = PG_ERR_TIM;
}
/* Configure TIM3 as master & use the update event as Trigger Output (TRGO) */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if(HAL_TIMEx_MasterConfigSynchronization(&TimMasterHandle, &sMasterConfig) != HAL_OK){
xPGERR = PG_ERR_TIM;
}
/* Start PWM Timer3*/
if(HAL_TIM_PWM_Start(&TimMasterHandle, TIM_CHANNEL_1) != HAL_OK){
xPGERR = PG_ERR_TIM;
}
if(HAL_TIM_Base_Start_IT(&TimMasterHandle) != HAL_OK){
xPGERR = PG_ERR_TIM;
}
return xPGERR;
}
1) With this configuration i get some really odd behaviour. After including the data structure:
PG_HandleTypeDef hPG_timer;
hPG_timer.PLS.Prescaler = 139;
hPG_timer.PLS.Period = 60000;
hPG_timer.PLS.DutyCycle = 30000;
hPG_timer.PLS.RepetitionCounter = 5;
hPG_timer.PLS.PercentChange = 0;
After that code snipped, I don't get any output on PIN PB4 (Master - TIM3) which should still be toggled at 1Hz.
2) To get even more confusing, when I substitute the code block with a handle:
PG_HandleTypeDef hPG_timer;
PG_HandleTypeDef *hPG_timer;
hPG_timer = &hPG_timer_config;
hPG_timer.PLS.Prescaler = 139;
hPG_timer.PLS.Period = 60000;
hPG_timer.PLS.DutyCycle = 30000;
hPG_timer.PLS.RepetitionCounter = 5;
hPG_timer.PLS.PercentChange = 0;
Now I can see the output on PB4 (Master - TIM3) with 1Hz but the output polarity of PA9 (Slave - TIM1) is reversed.
I tried to investigate the problem, I focused on the stack/heap of the FreeRTOS. I tested the system with large heap/stack = (uint32_t) 65535; I couldn't observe any changes in the behaviour.
I hope somebody came across a similar problem or has an idea how to resolve this. I'm thankful for any input in this, I'm at the end of my knowledge unfortunately.
Edit:
I spend some more time with the problem, and I think I can be more specific. In case of the pointer use, the TimMasterHandle is locked right after the initialization. If I unlock the handle TimMasterHandle.lock = HAL_UNLOCK; all works well, but that is just masking the problem and i would like to know where this is coming from.
It some how looks still like an heap or stack problem. Is there any way, I can check for heap or stack overflow. I am using Keil uVision 5.10.
Thank you for your time and help,
eimer

So I contacted the E-Mail support of ST.
The rather simple answer I got was -
Initialize your timer handles e.g.:
PG_HandleTypeDef hPG_timer = {0};
Seems to resolve the odd behaviour.
I hope somebody finds this usefull.
enjoy your day
eimer

Related

Using DCMI Interface but only receiving 0xA603A603 before hard fault

For my master thesis I am trying to receive data over DCMI with the STM32H742. As an image sensor I am using the NOIV2SN1300A. It sends data over 10 data lines, this data differs (so not always 0xA603A603). To reduce data size I have activated binning and subsampling.
I am using DMA to transfer the data received by DCMI into the internal SRAM at address 0x24000000. After a few telegrams (of 0xA603A603) the uC goes into hard fault and infinite loop. I am not sure why this error occurs. Here is my config for DMA and DCMI:
/* DCMI DMA Init */
/* DCMI Init */
hdma_dcmi.Instance = DMA1_Stream0;
hdma_dcmi.Init.Request = DMA_REQUEST_DCMI;
hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;//WORD;
hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dcmi.Init.Mode = DMA_DOUBLE_BUFFER_M0;
hdma_dcmi.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_dcmi.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_dcmi.Init.MemBurst = DMA_MBURST_SINGLE;
//hdma_dcmi.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hdcmi,DMA_Handle,hdma_dcmi);
HAL_NVIC_SetPriority(DCMI_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DCMI_IRQn);
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
hdcmi.Instance = DCMI;
hdcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
hdcmi.Init.PCKPolarity = DCMI_PCKPOLARITY_FALLING; //Todo:???
hdcmi.Init.VSPolarity = DCMI_VSPOLARITY_HIGH;
hdcmi.Init.HSPolarity = DCMI_HSPOLARITY_HIGH;
hdcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
hdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_10B;
hdcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
hdcmi.Init.ByteSelectMode = DCMI_BSM_OTHER;//DCMI_BSM_ALL;
hdcmi.Init.ByteSelectStart = DCMI_OEBS_ODD;
hdcmi.Init.LineSelectMode = DCMI_LSM_ALL;
hdcmi.Init.LineSelectStart = DCMI_OELS_ODD;
if (HAL_DCMI_Init(&hdcmi) != HAL_OK)
{
Error_Handler();
}
uint32_t DataSizeImageSensor = 0xB160;
DMA_BUFFER uint32_t AddressFrameBuffer[0xB160];
HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_SNAPSHOT, (uint32_t)AddressFrameBuffer, DataSizeImageSensor);
void MPU_Config (void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* Disable the MPU */
HAL_MPU_Disable();
/* Configure the MPU attributes for SDRAM */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; //Cache is incoherent with CPU for DMA usage
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enable the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
Any idea why this error occurs? Like I said, I receive data, I am sure the sensor sends viable data (so something else then 0xA603A603), but I get only the same data by DCMI before hard fault. At this current setup I transfer 64 telegrams, then the hard fault occurs. Furthermore I disabled the cache for the SRAM1, as there are problems regarding cache/DMA/CPU coherence. I am not quite sure how to proceed, as it looks to me like it is a setup error. Maybe an overrun by DCMI?
Note: The code above doesn't actually occur in this order. That are just the relevant parts (at least from what I expect to be relevant).
I found other posts about this problem, where the error was a slow system clock. As my system clock is 475 MHz and the HCLK3 Clock (which is used by DCMI for sampling) is 237.5 MHz I can rule out a Clock problem. The datasheet says the HCLK Clock has to be 2.5 times faster then DCMI Clock (which is set by the image sensor with 62 Mhz).

Using DMA controller to transmit UART

I have been trying exhaustively to program my STM32F7xx microcontroller to use DMA to transmit to UART. Three things are going on and I cannot explain or understand why this is happening, and hope somebody can help me out with this issue.
In the main while loop, I am printing three interrupt status flags. These flags are set if the corresponding ISR has been called. I added this to check if the ISR was called without adding blocking statements in the ISRs. None of the interrupts, however, are called.
The DMA only transmits 1 sequence of 513 bytes. When I modify the while loop in my main to only contain HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);, nothing changes, the function is only called/executed once.
In the while loop, I print the status of the ISR flags. After printing, the CPU stops/locks/shutdown/exits the while loop. At first, I thought I was congesting the AHB by using the UART to my terminal and the UART for the DMA controller. I disabled my terminal, and used LEDs, this didn't change anything.
Currently, the only running hypothesis I have is that my CPU somehow has interrupts disabled.
#include "stm32f7xx.h"
#include "mbed.h"
uint8_t dmxBuffer[513];
volatile bool irqA = false;
volatile bool irqB = false;
volatile bool irqC = false;
Serial pc(USBTX, USBRX, 115200);
UART_HandleTypeDef handleUart4;
DMA_HandleTypeDef handleDma;
void initialiseGPIO()
{
GPIO_InitTypeDef GPIO_InitStruct;
__GPIOA_CLK_ENABLE();
/**UART4 GPIO Configuration
PA0 ------> USART4_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_UART4;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void initialiseDMAController()
{
/* DMA controller clock enable */
__DMA1_CLK_ENABLE();
/* Peripheral DMA init*/
handleDma.Instance = DMA1_Stream4;
handleDma.Init.Channel = DMA_CHANNEL_4;
handleDma.Init.Direction = DMA_MEMORY_TO_PERIPH;
handleDma.Init.PeriphInc = DMA_PINC_DISABLE;
handleDma.Init.MemInc = DMA_MINC_ENABLE;
handleDma.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE;
handleDma.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
handleDma.Init.Mode = DMA_NORMAL;
handleDma.Init.Priority = DMA_PRIORITY_MEDIUM;
handleDma.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&handleDma);
//Define
__HAL_LINKDMA(&handleUart4,hdmatx,handleDma);
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
}
void initialiseUart()
{
__UART4_CLK_ENABLE();
handleUart4.Instance = UART4;
handleUart4.Init.BaudRate = 250000;
handleUart4.Init.WordLength = UART_WORDLENGTH_8B;
handleUart4.Init.StopBits = UART_STOPBITS_2;
handleUart4.Init.Parity = UART_PARITY_NONE;
handleUart4.Init.Mode = UART_MODE_TX;
handleUart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
handleUart4.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&handleUart4);
/* Peripheral interrupt init*/
HAL_NVIC_SetPriority(UART4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(UART4_IRQn);
}
/* This function handles DMA1 stream4 global interrupt. */
void DMA1_Stream4_IRQHandler(void)
{
irqA = true;
HAL_DMA_IRQHandler(&handleDma);
}
/* This function handles the UART4 interups */
void UART4_IRQHandler(void)
{
irqB = true;
HAL_UART_IRQHandler(&handleUart4);
}
//HAL_UART_TxCpltCallback
/* This callback function is called when the DMA successfully transmits all scheduled bytes. */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
irqC = true;
}
int main(void)
{
/* Reset of all peripherals */
HAL_Init();
//Initialise peripherals
initialiseGPIO();
initialiseDMAController();
initialiseUart();
//Fill buffer with test data
for (int x = 0; x < 100; x++)
{
dmxBuffer[x] = x;
}
//Now instruct the UART peripheral to transmit 513 bytes using the DMA controller.
HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);
while(1)
{
pc.printf("irqA: %d - irqB: %d - irqC: %d\r\n", irqA, irqB, irqC);
wait_ms(100); //Wait to see if any of the interupt handlers / callback functions are called
//Check if all bytes are sent, if so, retransmit
if (irqC)
{
irqC = false;
HAL_UART_Transmit_DMA(&handleUart4, dmxBuffer, 513);
}
}
}
Check the interrupt vector table
Verify that the vector table does indeed contain a pointer to your handler function, not to some generic placeholder with an infinite loop (that makes the program hang).
Search for the name of the interrupt handler function in the entire source code. Is there any other object or #define that could interfere with the function definition, or the vector table entry?
Change the name of the handler, both the function definition and the vector table entry. Does it still compile? When not, does adding extern "C" to the function prototype help?
Look up the address of the handler in the .map file, and the offset entry for the interrupt in the vector table provided in the Reference Manual (Nested vectored interrupt controller (NVIC) / Interrupt and exception vectors). Check the contents of the compiled program binary file at the given offset. Does it match the address found in the .map file + 1?
Check the value at NVIC->VTOR plus the offset while running the program. It should be the same as the one found in the binary. If not, see that the VTOR register is set to the beginning of the right vector table.

Using STM32 Timer->GPIO transfer to handle WS2812B LED timing data

I've been working on a lighting controller, but haven't had any luck in transferring data through GPIO. I'm using the STM32F303VCT6, and HAL library. I used the WS2812B Library for STM32F3 by Hubmartin as reference, modifying it to handling LED timing data transfer in a single DMA transfer as opposed to bitbanding timing data into a two LED length buffer through circular DMA.
My plan has been to use DMA to start every GPIO that's set to LED output, to output 'high' on timer update event. Then on event CC1 to write given pins to 'low' through buffer data. And then on event CC2 to set all pins 'low'. This should allow me to handle the timing data for multiple strips in parallel. Here is my implementation:
To initialize timer:
static void TIM2_init(void){
__HAL_RCC_TIM2_CLK_ENABLE();
tim_period = SystemCoreClock / 800000;
uint32_t cc1 = (10 * tim_period) / 36;
uint32_t cc2 = (10 * tim_period) / 15;
Tim2Handle.Instance = TIM2;
Tim2Handle.Init.Period = tim_period;
Tim2Handle.Init.RepetitionCounter = 0;
Tim2Handle.Init.Prescaler = 0;
Tim2Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
Tim2Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Init(&Tim2Handle);
tim2OC1.OCMode = TIM_OCMODE_PWM1;
tim2OC1.OCPolarity = TIM_OCPOLARITY_HIGH;
tim2OC1.Pulse = cc1;
tim2OC1.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC1, TIM_CHANNEL_1);
tim2OC2.Pulse = cc2;
HAL_TIM_PWM_ConfigChannel(&Tim2Handle, &tim2OC2, TIM_CHANNEL_2);
}
To initialize DMA:
static void DMA_init(void){
__HAL_RCC_DMA1_CLK_ENABLE();
dmaUpdate.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaUpdate.Init.PeriphInc = DMA_PINC_DISABLE;
dmaUpdate.Init.MemInc = DMA_MINC_DISABLE;
dmaUpdate.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaUpdate.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaUpdate.Init.Mode = DMA_NORMAL;
dmaUpdate.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaUpdate.Instance = DMA1_Channel2;
HAL_DMA_Init(&dmaUpdate);
__HAL_LINKDMA(&Tim2Handle, hdma[TIM_DMA_ID_UPDATE], dmaUpdate);
dmaCC1.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaCC1.Init.PeriphInc = DMA_PINC_DISABLE;
dmaCC1.Init.MemInc = DMA_MINC_ENABLE;
dmaCC1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaCC1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
dmaCC1.Init.Mode = DMA_NORMAL;
dmaCC1.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaCC1.Instance = DMA1_Channel5;
HAL_DMA_Init(&dmaCC1);
__HAL_LINKDMA(&Tim2Handle, hdma[TIM_DMA_ID_CC1], dmaCC1);
dmaCC2.Init.Direction = DMA_MEMORY_TO_PERIPH;
dmaCC2.Init.PeriphInc = DMA_PINC_DISABLE;
dmaCC2.Init.MemInc = DMA_MINC_DISABLE;
dmaCC2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dmaCC2.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dmaCC2.Init.Mode = DMA_NORMAL;
dmaCC2.Init.Priority = DMA_PRIORITY_VERY_HIGH;
dmaCC2.Instance = DMA1_Channel7;
HAL_DMA_Init(&dmaCC2);
__HAL_LINKDMA(&Tim2Handle, hdma[TIM_DMA_ID_CC2], dmaCC2);
dmaCC2.XferCpltCallback = DMA_TransferCompleteHandler;
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
To begin a transfer:
static void WS2812_sendbuf(){
ws2812b.transferComplete = 0;
HAL_DMA_Start(&dmaUpdate,(uint32_t)WS2812_IO_High, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE);
HAL_DMA_Start(&dmaCC1,(uint32_t)ws2812bDmaBitBuffer, (uint32_t)&WS2812B_PORT->BRR, BUFFER_SIZE);
HAL_DMA_Start_IT(&dmaCC2,(uint32_t)WS2812_IO_Low, (uint32_t)&WS2812B_PORT->BSRR, BUFFER_SIZE);
__HAL_TIM_ENABLE_DMA(&Tim2Handle, TIM_DMA_UPDATE);
__HAL_TIM_ENABLE_DMA(&Tim2Handle, TIM_DMA_CC1);
__HAL_TIM_ENABLE_DMA(&Tim2Handle, TIM_DMA_CC2);
__HAL_TIM_ENABLE(&Tim2Handle);
}
To callback on completion of DMA output:
void DMA1_Channel7_IRQHandler(void){
HAL_DMA_IRQHandler(&dmaCC2);
}
void DMA_TransferCompleteHandler(DMA_HandleTypeDef *DmaHandle){
WS2812B_PORT->BSRR = WS2812_IO_Low[0];
__HAL_TIM_DISABLE_DMA(&Tim2Handle, TIM_DMA_UPDATE);
__HAL_TIM_DISABLE_DMA(&Tim2Handle, TIM_DMA_CC1);
__HAL_TIM_DISABLE_DMA(&Tim2Handle, TIM_DMA_CC2);
__HAL_TIM_DISABLE(&Tim2Handle);
ws2812b.transferComplete = 1;
}
Although I can verify that the initial implementation works as intended, there's some glitchy behavior in the current HAL driver, which I am attempting to overcome through having all my data available before the timing data transmission begins.
In my current implementation, I send a single data buffer and begin the timing data transmission, and then delay 100 milliseconds before starting the process again. I am confused to find that my implementation doesn't appear to send out any data at all through GPIO, and I assume that I've made mistakes in my state logic / timer start. Does anyone see a mistake that I've made to cause no output?

Reading STM32 timer value

I am using a STM32F103 chip and I am trying to configure and use one of the timers. I have used STM32CubeMX to generation code which initializes Timer 2. I start the timer by calling HAL_TIM_Base_Start. Then, in a loop, I print out the current timer value via a call to htim2.Instance->CNT, or alternately by calling the macro __HAL_TIM_GetCounter (which I believe just returns the same value). However, no matter what I do, the count value shows up as zero. I have also tried calling __TIM2_CLK_ENABLE() at the beginning, but it makes no difference.
I have searched for a solution and have found a couple of questions about this issue, but have not found the solution.
Does anyone know what I am doing wrong?
Thanks.
Here is the routine that initializes the timer. This code was generated by STM32CubeMX and I have not modified it:
/* TIM2 init function */
static void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
Then in the main I attempt to start the timer and attempt to print out it's value. This is the code that I use to do that:
__TIM2_CLK_ENABLE();;
HAL_TIM_Base_Start(&htim2);
while (true)
{
Serial.println((long) __HAL_TIM_GetCounter(&htim2));
delay(100);
}
The 'Serial' class is a class that I wrote which communicates with my PC via a USB serial port.
Try it without HAL, it's not complicated.
void start_TIM2() {
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
TIM2->CR1 |= TIM_CR1_EN;
}
uint16_t read_TIM2() {
return TIM2->CNT;
}
Setting the value of
htim2.Init.Period = 0;
zero initializes the auto reload register (ARR) not a very handy default choice of cubeMX, you probably want an ARR value of 0xFFFFFFFF
The accepted answer relies on the ARR value after reset of 0xFFFFFFFF without mentioning it, more luck than wisdom if you ask me
The ARR (htim2.Init.Period) shouldn't be 0. It will try to count uptil...0! Put some 16 bit integer there. Good Luck!
I will show you some formulas to keep in mind: (refer: AN4776)
. Frequency = Fclk(timer) / (prescaler + 1)
For example, you chose prescaler = 0, it implies that your timer finishes counting [0: count) in a period of 1 / 80MHz, in case the SystemClock is configured like this (you should check the value of the clock and the prescaler to determine the Update frequency).
. #1_count(s) = 1 / Frequency
. period(s) = #1_count * (counter + 1)
--> Let's see it with an example:
SystemClock = 72MHz, requires a 1us resolution timer and a 1ms period.
. for a 1us of resolution -> Frequency = 1Mhz
'1MHz = 72MHz / (prescaler + 1)' -> prescaler = 71
. so that the timer interrupts every one millisecond we must calculate how much it should count:
'1ms = 1us * (counter + 1)' -> count = 999
with these values we configure the following:
htim2.Init.Prescaler = 71;
htim2.Init.Period = 999;
where the timer will count from 0: 999 in steps of 1uS.
Your code has two problems, the timer frequency is too high and it only counts from 0: 1, so you will never be able to see the increase in counts.

STM Nucleo I2C not sending all data

Edit:
The solution was to turn down the I2C clock in the initialization block. Although the STM could handle it, the data sheet for the LCD stated it could handle only up to 10kHz.
For the DMA there is an IRQ that must be enabled and setup in the CubeMX software that will enable DMA TX/RX lines.
I'm using an STM32 - Nucleo-F401RE board with freeRTOS. I've used freeRTOS a bit recently, but I have never really used I2C.
Trying to setup a simple LCD display using the I2C drivers that CubeMX generates.
So far it only sends about half the data I request to send.
I've tested it with the simple "show firmware" command and this works. So I can verify that the I2C instance is setup correctly.
/* I2C1 init function */
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
It has international pull-up resistors set as well.
/* vdebugTask function */
void vdebugTask(void const * argument)
{
/* USER CODE BEGIN vdebugTask */
/* Infinite loop */
for(;;)
{
char hi[6];
hi[0] = 'h';
hi[1] = 'e';
hi[2] = 'y';
hi[3] = 'a';
hi[4] = 'h';
hi[5] = '!';
HAL_I2C_Master_Transmit_DMA(&hi2c1, (0x50), hi, 6);
vTaskDelay(10);
}
/* USER CODE END vdebugTask */
}
This is the code I am trying to run, I have not changed the HAL function at all. I don't think that it could be more simple than this, however this is all that happens.
I followed the timing constraints in the data sheet for the LCD, and the CubeMX software didn't warn or state anywhere that their I2C drivers had any special requirements. Am I doing something wrong with the program?
I have also tried using the non-DMA blocking mode polling transfer function that was also created by CubeMX
HAL_I2C_Master_Transmit(&hi2c1, (0x50), hi, 6, 1000);
This is even worse and just continuously spams the screen with unintelligible text.
The solution was to turn down the I2C clock in the initialization block. Although the STM could handle it, the data sheet for the LCD stated it could handle only up to 10kHz.
For the DMA there is an IRQ that must be enabled and setup in the CubeMX software that will enable DMA TX/RX lines.
Note that the clock still must adhere to the hardware limitations. I assume that roughly 20% less than maximum stated in the data sheet will suffice. For my LCD this means that I am going to be using 80kHz.
First go to configuration :
And then click on DMA to setup a DMA request. I've only selected TX as I don't care about an RX DMA from the LCD.

Resources