STM32+CubeMX+HAL Library using pwm toggle output failed - stm32

I understand its principle is to use PWM comparison function when CRR = CNT is triggered interrupt and flip level. I set the ARR to 65535 to automatically add it up again. The CRR value is adjusted for each incoming interrupt, however the PWM waveform does not seem to be ideal
This is my cubemx setting
My TIM_IT code
void TIM3_IRQHandler(void)
{
/\* USER CODE BEGIN TIM3_IRQn 0 \*/
if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_CC1) != RESET)
{
__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_CC1);
TIM3->CCR1+=10000;
return;
}
if (__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_CC2) != RESET)
{
__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_CC2);
TIM3->CCR2+=5000;
return;
}
/\* USER CODE END TIM3_IRQn 0 */*
HAL_TIM_IRQHandler(&htim3);
/ USER CODE BEGIN TIM3_IRQn 1 \*/
/\* USER CODE END TIM3_IRQn 1 \*/
}\

Related

STM32L4A6 - ISR is processed twice

Issue
I have an input signal that shall trigger an interrupt. The ISR then shall toggle an output pin 24 times.
Having it set up stright forward I am facing the issue that the ISR is executed twice.
System
IDE: STM32CubeIDE v1.10.0
uC: STM32L4A6 (NUCLEO-L4A6ZG)
Pin config:
PC12 (DATA_READY_NEG_EDGE) = External interrupt, falling edge (externally pulled down with 100k and 100n)
PC11 (ADC_SPI_CLK) = Output
Code
The auto code generator pulls out the following code
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
The callback function looks like this (but I don't think that this is part of the issue):
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == DATA_READY_NEG_EDGE_Pin) // INT Source is pin PC12
{
HAL_GPIO_TogglePin(LED_RED_GPIO_Port, LED_RED_Pin); // Toggle LED
for (int var = 0; var < 24; ++var)
{
HAL_GPIO_TogglePin(ADC_SPI_CLK_GPIO_Port, ADC_SPI_CLK_Pin);
HAL_GPIO_TogglePin(ADC_SPI_CLK_GPIO_Port, ADC_SPI_CLK_Pin);
}
}
}
This way the interrupt is falsely triggered twice.
Interchange the sequence of "CLEAR" and "Callback" function call in the IRQHandler, the ISR is correctly only called once. But this is a hack and every time I generate the code it is reverted again, so for sure not a solution.
What issue do I have and what could be the workaround?
Thx for any support!

Using DMA with two UART peripherals - is it possible?

I want to connect two UART peripherals using STM32G0 microcontroller via DMA. Not knowing the length of the messages in forward, I'm using function HAL_UARTEx_ReceiveToIdle_DMA() in order to receive them. Here is the part of my code:
main.h
.
.
.
StartDMAReceptionOverUART1();
StartDMAReceptionOverUART4();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(10);
}
.
.
.
void StartDMAReceptionOverUART1(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_modulePort.huart, m_modulePort.rxBuffer, m_modulePort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_TC);
}
void StartDMAReceptionOverUART4(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_meterPort.huart, m_meterPort.rxBuffer, m_meterPort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_TC);
}
.
.
.
These functions are similar: first HAL_UARTEx_ReceiveToIdle_DMA() is checked, then Half Transfer and Transfer Complete interrupts are disabled in order to relieve processor (I need only IDLE interrupt). The problem is inside StartDMAReceptionOverUART1() function, HAL_UARTEx_ReceiveToIdle_DMA() never returns HAL_OK and program jumps on Error_Handler(). On the other hand, StartDMAReceptionOverUART4() works perfectly fine. What could be the problem?
Also, here is the receive callback function, also written inside main.h:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == m_meterPort.huart->Instance) // huart == UART4
{
memcpy(m_modulePort.txBuffer, m_meterPort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_modulePort.huart, m_modulePort.txBuffer, Size);
StartDMAReceptionOverUART4();
}
else if (huart->Instance == m_modulePort.huart->Instance) // huart == UART1
{
memcpy(m_meterPort.txBuffer, m_modulePort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_meterPort.huart, m_meterPort.txBuffer, Size);
}
else
{
return;
}
}
Callback function, in dependence of the periphery, will copy received data to a buffer and send it to the other periphery (functions memcpy() and HAL_UART_Transmit_DMA()). DMA over UART4 is in Normal mode, therefore StartDMAReceptionOverUART4() is called, inside which is HAL_UARTEx_ReceiveToIdle_DMA(). On the other hand, DMA over UART1 is in Circular mode, so there is no need for calling StartDMAReceptionOverUART4().

STM32 UART : HAL_UART_Transmit_IT Not working with Task

My UART tx Working with blocking mode and before FreeRtoss kernel start. But if I try to transmit inside task Not working( see below code ). Is any special code needed ?
enter code here
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
/* Infinite loop */
for(;;)
{
HAL_UART_Transmit_IT(&huart2, hi, sizeof(hi));
osDelay(1000);
}
/* USER CODE END 5 */
}

How to setup the standby mode on a STM32F4 MCU running an RTOS and waking it up after?

I like to put my STM32F412 into deep sleep mode and wake it after by pressing a button. This code should run together with an RTOS(Zephyr). So when executing the code, to put the device into deep sleep, other tasks etc. are active.
So I am looking for a bullet proof approach, that makes it sure that the STM32F412 goes to standby and wakeup after.
so far my (not working code):
#define POWER_WAKEUP_PIN LL_PWR_WAKEUP_PIN2
// set PC0 as input gpio
LL_GPIO_SetPinPull(GPIOC, LL_GPIO_PIN_0, LL_GPIO_PULL_NO);
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_0, LL_GPIO_MODE_INPUT);
// activate EXTI line 0
LL_EXTI_InitTypeDef EXTI_InitStruct = {0};
LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_ALL_0_31);
EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_0;
EXTI_InitStruct.LineCommand = ENABLE;
EXTI_InitStruct.Mode = LL_EXTI_MODE_EVENT;
EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING;
LL_EXTI_Init(&EXTI_InitStruct);
// put to standby
LL_PWR_DisableWakeUpPin(POWER_WAKEUP_PIN);
LL_PWR_ClearFlag_WU();
LL_PWR_EnableWakeUpPin(POWER_WAKEUP_PIN);
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
LL_LPM_EnableDeepSleep();
__WFI();
Its using the stm32 LL HAL. Any ideas what is missing
I found a working solution. It consists of 2 parts:
add an idle thread that calls "__WFI()". In my case I use the main thread of Zephyr and set its prio to the lowest of the system threads. If nothing to do for the system this thread is active and it does nothing else than sleeping.
setup a function that enables the RTC which triggers a wake up event after some time (in my case 1sec). Put the MCU to sleep mode with . Clk the wakeup circut via RTC. After the wakeup event check the wakeup condition is checked. In my case I check the state of the wakeup pin and an other pin. If the condition is full filled, a reset is generated.
Following some code snipes for the ZephyrRTOS:
void rtc_setupDeepsleepWakeUp(bool on) {
if (true == on) {
/*
Programming the wakeup timer
The following sequence is required to configure or change the wakeup timer auto-reload
value (WUT[15:0] in RTC_WUTR):
1. Clear WUTE in RTC_CR to disable the wakeup timer.
2. Poll WUTWF until it is set in RTC_ISR to make sure the access to wakeup auto-reload
counter and to WUCKSEL[2:0] bits is allowed. It takes 1 to 2 RTCCLK clock cycles
(due to clock synchronization).
3. Program the wakeup auto-reload value WUT[15:0] and the wakeup clock selection
(WUCKSEL[2:0] bits in RTC_CR).Set WUTE in RTC_CR to enable the timer again.
The wakeup timer restarts down-counting. Due to clock synchronization, the WUTWF
bit is cleared up to 2 RTCCLK clocks cycles after WUTE is cleared.
note on step 3:
32768Hz -> 32768 decrements per second
now calc the value for the timer
32768/ 16 = 0x800
0x800 -> counter -> 1sec
*/
LL_RCC_EnableRTC();
HAL_RTCEx_SetWakeUpTimer_IT(&rtc.hrtc, 0x800, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
irq_enable(RTC_WKUP_IRQn);
} else {
HAL_RTCEx_DeactivateWakeUpTimer(&rtc.hrtc);
irq_disable(RTC_WKUP_IRQn);
}
}
void power_sleep(void) {
__WFI();
}
#define THREAD_PRIO_idle 12
void power_deepSleep(void) {
unsigned int key;
LOG_INF("preparing device to deep sleep");
power_disableAllPeriphals();
power_clearAllInterrupts();
gpio_enableWakeupButton();
rtc_setupDeepsleepWakeUp(true);
for (;;) {
HAL_SuspendTick();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
HAL_ResumeTick();
// break condition of low power mode
// button pressed or usb insert
if (
(0 == gpio_get_powerButton_state()) ||
(1 == gpio_get_vbus_state())
) {
rtc_setupDeepsleepWakeUp(false);
sys_reboot(SYS_REBOOT_COLD);
}
}
rtc_setupDeepsleepWakeUp(false);
sys_reboot(SYS_REBOOT_COLD);
LOG_ERR("ahhhh something went wrong");
}
void main(void)
{
power_recoverFromDeepSleep();
LOG_INF("start");
...
LOG_INF("start completed");
LOG_DBG("set main prio to lowest(idle)");
k_thread_priority_set(k_current_get(), THREAD_PRIO_idle);
while(1) {
power_sleep();
}
}

Using signal() inside handler function

I have taken this example from GNU library. And I wonder why they call signal() function twice, first time in main() when setting up the signal handler and second time inside handler function itself.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
/* This flag controls termination of the main loop. */
volatile sig_atomic_t keep_going = 1;
/* The signal handler just clears the flag and re-enables itself. */
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm);
}
void
do_stuff (void)
{
puts ("Doing stuff while waiting for alarm....");
}
int
main (void)
{
/* Establish a handler for SIGALRM signals. */
signal (SIGALRM, catch_alarm);
/* Set an alarm to go off in a little while. */
alarm (2);
/* Check the flag once in a while to see when to quit. */
while (keep_going)
do_stuff ();
return EXIT_SUCCESS;
}
Now my code...
void createTimer(long freq_nanosec)
{
timer_t timerid;
struct sigevent sev;
struct itimerspec timerint;
struct sigaction saction;
/* Establish handler for timer signal */
saction.sa_flags = 0;
saction.sa_handler = OnTimer;
sigemptyset(&saction.sa_mask);
sigaddset (&saction.sa_mask, SIGIO);
if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
else printf("OnTimer handler created\n");
/* Create real time signal */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCKID, &sev, &timerid) == -1) error("timer_create");
else printf("timer ID is 0x%lx\n", (long) timerid);
/* Arm the timer */
timerint.it_value.tv_sec = timerint.it_interval.tv_sec =
freq_nanosec / 1000000000;
timerint.it_value.tv_nsec = timerint.it_interval.tv_nsec =
freq_nanosec % 1000000000;
if (timer_settime(timerid, 0, &timerint, NULL) == -1)
error("timer_settime");
else printf("Timer armed\n");
}
From the man page for signal, we see that when a signal arrives:
first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum.
So after the signal arrives, further signals will revert to default behavior. In your sample code, the handler is choosing to re-set the signal handler so further signals will be handled in the same manner as the first.
This is noted in the comment for the function catch_alarm in the code you found.
There are two popular versions of signal, which differ in whether the disposition of a signal is reset to the default when the handler is called, and whether a signal is blocked for the duration of its handler's execution.
The standard says those two behaviors are implementation-defined. The first code sample
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm);
}
is assuming that the implementation may reset the signal disposition to the default when the handler is called. That's like calling signal(sig, SIG_DFL) in the first line of the handler. You almost never want that, because the next time a SIGALRM signal comes in, the default action is for the program to be killed. So the handler calls signal(sig, catch_alarm) to re-establish itself as the handler.
Your second code sample
saction.sa_flags = 0;
saction.sa_handler = OnTimer;
sigemptyset(&saction.sa_mask);
sigaddset (&saction.sa_mask, SIGIO);
if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
uses sigaction, which is generally preferred over signal because you can specify exactly the behavior you want. The standard says
new applications should use sigaction() rather than signal().
When .sa_flags has the SA_RESETHAND flag on, the disposition of the signal is reset to the default when the handler starts, just like in (one version of) signal.
But in your case, that flag is off because you set .sa_flags to 0, so you don't need to write any code to re-establish the handler.