stm32f4 DMA does not always start after suspending - stm32

So this question is kind of a "sequel" of this one: Stm32f4: DMA + ADC Transfer pausing.
Again, I am trying to implement such an algorithm:
Initialize DMA with ADC in tripple interleaved mode on one channel
Wait for an external interrupt
Suspend DMA transfer and the ADC
Send the buffered data from memory through USART in the interrupt
Resume the DMA and ADCs
Exit the interrupt, goto 2.
The DMA and ADC suspends and resumes, but sometimes (in about 16% of interrupt calls) the resuming fails - DMA just writes first measurement from the ADCs and stops until next interrupt, in which DMA and ADC are restarted (since they are suspended and resumed again) and - well, everything returns back to normal until next such bug.
I've tried suspending DMA just like the Reference manual says:
In order to restart from the point where the transfer was stopped, the
software has to read the DMA_SxNDTR register after disabling the
stream by writing the EN bit in DMA_SxCR register (and then checking
that it is at ‘0’) to know the number of data items already collected.
Then:
– The peripheral and/or memory addresses have to be updated in order to adjust the address pointers
– The SxNDTR register has to be updated with the remaining number of data items to be transferred (the value read when the stream was disabled)
– The stream may then be re-enabled to restart the transfer from the point it was stopped
The only actual difference is in the written NDTR value while resuming DMA working. In my case it is buffer_size, in the RefMan case - it is the value read while pausing the DMA. In the RefMan case, DMA never starts again after pausing. In my case, as I said above, it starts, but not always.
How can I prevent this from happening?
The interrupt code looks like this currently:
void EXTI4_IRQHandler(void) {
uint16_t temp = DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TEIF0);
if(EXTI_GetITStatus(EXTI_Line4) != RESET) {
uint16_t fPoint1 = 0;
uint16_t fPoint2 = 0;
//Some delay using the TIM2
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
//Measure the first point NDTR
fPoint1 = DMA2_Stream0->NDTR;
while(TIM_GetITStatus(TIM2, TIM_IT_Update) != SET) {};
//Measure the second point here.
fPoint2 = DMA2_Stream0->NDTR;
if(fPoint1 == fPoint2) {
//The NDTR does not change!
//If it does not change, it is stuck at buffer_size - 1
}
//Disable the timer
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_Cmd(TIM2, DISABLE);
DMA_Cmd(DMA2_Stream0, DISABLE);
//Wait until the DMA will turn off
while((DMA2_Stream0->CR & (uint32_t)DMA_SxCR_EN) != 0x00) {};
//Turn off all ADCs
ADC_Cmd(ADC1, DISABLE);
ADC_Cmd(ADC2, DISABLE);
ADC_Cmd(ADC3, DISABLE);
//Send all the data here
//Turn everything back on
//Turn the DMA ON again
DMA_SetCurrDataCounter(DMA2_Stream0, BUFFERSIZE);
DMA_Cmd(DMA2_Stream0, ENABLE);
while((DMA2_Stream0->CR & (uint32_t)DMA_SxCR_EN) == 0x00) {};
//See note # RefMan (Rev. 12), p. 410
ADC->CCR &= ~((uint32_t)(0x000000FF));
ADC->CCR |= ADC_TripleMode_Interl;
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
ADC_Cmd(ADC3, ENABLE);
while((ADC1->CR2 & (uint32_t)ADC_CR2_ADON) == 0) {};
while((ADC2->CR2 & (uint32_t)ADC_CR2_ADON) == 0) {};
while((ADC3->CR2 & (uint32_t)ADC_CR2_ADON) == 0) {};
ADC_SoftwareStartConv(ADC1);
}
EXTI_ClearITPendingBit(EXTI_Line4);
}

I've found the solution myself. I was thinking it was a DMA problem; however, it turned ot to be ADC's problem.
The OVR flag in ADCx->CR register was always set when the transfer was "stuck". So, I added an interrupt to the ADC overrun situation and restarted DMA & ADC in it. The problem is solved now.

Related

Does HAL_NVIC_SetPendingIRQ call the ISR to execute?

I am really new to STM32 world so I came across this while reading:
void HAL_NVIC_SetPendingIRQ(IRQn_Type IRQn);
This will cause the interrupt to fire, as it would be generated by the hardware. A distinctive feature
of Cortex-M processors it that it is possible to programmatically fire an interrupt inside the ISR
routine of another interrupt.
I got this from the book Mastering STM32 (by Carmine Noviello page 208). From this I have understood that If we set this pending bit even from the main function, then the interrupt is generated.
So to try this out, I have written this code:
while (1)
{
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
for(int i = 0; i <10000000; i++);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
for(int i = 0; i <10000000; i++);
HAL_NVIC_SetPendingIRQ(EXTI0_IRQn);
}
}
along with this call back function
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_PIN){
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_15);
}
I have programmed GPIO_PIN_0 as source of interrupt and when I press the push button connected to PA0 the Interrupt works perfectly i.e. ISR is executed. To my surprice HAL_NVIC_SetPendingIRQ function doesn't generate interrupt. I don't understand why?
More Info:
I am using STM32F411VET6 DISCO board
I am using STM32CubeIDE to program the board
Thank you #Tagli. I have found the function HAL_GPIO_EXTI_IRQHandler inside stm32f4xx_hal_gpio.c file. Defalult definition was like this:
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
I got why the GPIO was not being toggled. It was the same reason you have commented above.
I have modified to prove it.
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
/* EXTI line interrupt detected */
HAL_GPIO_EXTI_Callback(GPIO_Pin);
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
HAL_GPIO_EXTI_Callback(GPIO_Pin);
}
}
Now the callback function is called when the HAL_NVIC_SetPendingIRQ(EXTI0_IRQn); is being called

How to implement UART1 Interrupts correctly on STM32f103xx while running a main programme?

I am trying to program my bluePill to blink an LED at the PB11 pin while echoing whats being send over the serial port UART1.
as far as my knowledge, Interrupts allows us to run the programme we want and while running it if any flag triggered an interrupt signal the program the control will be diverted to run the interrupt service routine while the original program is running, am I correct here?
So, I'm trying to keep the Green LED blinking and when I type anything on the serial port the red LED blinks while the green is blinking and the blue led must be always turned on unless data is being sent.
Problem 1:
The green led never blinks!
Problem 2:
Whenever sending letters or numbers through Arduino serial monitor the received echo is always 2 letters out of the entire send letters, also the echo is always on the same line, I mean not not on a newline
so typing Hello and pressing enter yields He and when typing hi there and pressing enter the it just adds the first two letters like so Hehi , why?
my code is
/* ********************** Project Description ***********************
STM32f103xx BluePill Board
PB10 = Green LED
PB11 = Blue LED (To be toggled)
PB0 = Red LED (PWM OUTPUT Controlling the Brightness)
PB9 = Push Button for toggling the state of the blue LED
PA0 = Potentiomater Pin (Analog Input)
USART1 Activated and Sends the Voltage of PA0 to the user1
*/
#include "stm32f1xx.h" // Include the MCU header
#include <stdbool.h> // Boolean Library header
#include <stdint.h>
// Prototypes:
void UART1_Init(void); //Enable UART1 on PA9(Tx) & PA10(Rx).
void portsEnable(void); //Enable Clock for desired MCU Ports.
void delay(uint32_t delay); //Intuduce Delays.
void pinsConfig(void); //Configure the used pins.
// Defines and Macros
int main(void)
{
// Inintialization:
portsEnable();
pinsConfig();
UART1_Init(); // Enable USART1 & interrupts # 8Mhz clock Speed only # 9600Bps
while(1)
{
// ******** Blink The green LED ***********************
GPIOB->BSRR = GPIO_BSRR_BS11;
delay(100000);
GPIOB->BSRR = GPIO_BSRR_BR11;
delay(100000);
} // End of while loop
} // End main() loop
// ************** Function Implimentation *****************************
void UART1_Init(void) // Initiallize USART1
{
// Reset Setting (8bit, one stop bit, no parity)
// Enable clock for UART1 First after already enabling the PortA clock
RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Enable Clock to the USART1 Module
// Pin Configuration for the USART1 Peripheral where Tx(PA9) = AF Push-Pull and Rx = Input Floating
// Setting Tx (PA9) Pin
GPIOA->CRH |= ((1<<4) | (1<<5)); // Set PA9 to Output 50Mhz Mode
GPIOA->CRH &= ~(1<<6); // Configure it to be an AF push-pull
GPIOA->CRH |= (1<<7); // Same as above^
// Setting Rx (PA10) pin
// Nothing to be set as the reset value makes it an input pin with floating configuration
// Set the Baud-Rate
USART1->BRR = 0x341; //# 8Mhz, USARTDIV = 8Mhz/(16*9600) = 52.083 -> 52=0x34 and 0.083 * 16 = 1.328 = 1 which is 0x1
// Enable Interrupts for the USART1 Module:
// A peripheral can generates a flag at a certain event, this flag can trigger an interrupt signal but first the certain event interrupt must be enabled and the peripheral interrupt as well and the global interrupts.
USART1->CR1 |= USART_CR1_TXEIE | USART_CR1_RXNEIE; // Enable the Transmit Data Register Empty Interrupt register and data received interrupt
// Enable the Tx, Rx, USART1 as a whole block
USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE | USART_CR1_UE);
// Enable the USART1 Global interrupt on NVIC "Nested Vectored Interrupt controller" side. The NVIC is the interrupt processing unit in the MCU.
NVIC_EnableIRQ(USART1_IRQn); // This function's name can't be changed!
}
// This is a global interrupt service routine, any flag from the USART1 will lead to the same ISR, to distinguesh which is which we check the the flags and if one is set then this what caused the interrupt
void USART1_IRQHandler(void) // This function's name must be the same as it's defined in the main libraries
{
// Check if we are here because we Received Data or simply the "RXNE flag is set".
if(USART1->SR & USART_SR_RXNE) // If Rx is Not Empty, or if we received Data, The USART1->SR register is going to change as it is controlled by the hardwart and we compare it to the value of the register USART_SR_RXNE which indicates a 1 at bit5
{
char temp = USART1->DR; // Read the 8bit data received fron the data register into a char called temp
USART1->DR = temp; // Put the same data in the data register to be resent again, here the data registers are clled shadow registers they are not the same registers from the hardware prospective but from programming prospective we use the same registers
while(!(USART1->SR & USART_SR_TC))
{
// Wait while the transmission completes and indicate the waiting process by flashing the RED led indicating data being sent.
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process) turn of the Blue LED
GPIOB->BSRR = GPIO_BSRR_BS1;
delay(10000);
GPIOB->BSRR = GPIO_BSRR_BR1;
}
}
// Check if we are here because the TXEIE is set "OR the Transmit complete" meaning we are ready to accept more data to transmit
if(USART1->SR & USART_SR_TXE)
{
// Handle transmit complete here: (Blink an LED)
GPIOB->BSRR = GPIO_BSRR_BS10; // When Ready to accept more data
}
else
{
GPIOB->BSRR = GPIO_BSRR_BR10; // When not ready to accept more data (e.g. while transmitting data process)
}
}
void portsEnable(void) /* Enable PortA and PortB */
{
// Enable clock for Ports (A & B) on "APB2" Bus.
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable PortA Clock
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; // Enable PortB Clock
}
void pinsConfig(void) //Configure the used pins.
{
//Set pin "PB1" as output push-pull (Red LED)
GPIOB->CRL |= ((1<<4) | (1<<5)); //Set Pin to Output 50Mhz max speed
GPIOB->CRL &= ~((1<<6) | (1<<7)); //Configure Pin as Push-Pull
//Set Pin "PB9" as Input Pulled-Up (Push Button Pin)
GPIOB->CRH &= ~(1<<6); //Set PB9 to input "pullup|pulldown"
GPIOB->CRH |= (1<<7);
GPIOB->ODR |= (1<<9); //Set PB9 input pin as Pull-up pin.
//Set pin "PB10" as output push-pull (Blue LED)
GPIOB->CRH |= ((1<<9) | (1<<8)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<11) | (1<<10)); //Configure Pin as Push-Pull
//Set pin "PB11" as output push-pull (Green LED)
GPIOB->CRH |= ((1<<12) | (1<<13)); //Set Pin to Output 50Mhz max speed
GPIOB->CRH &= ~((1<<14) | (1<<15)); //Configure Pin as Push-Pull
//Set pin PA0 as Analog input
GPIOA->CRL &= ~((1<<0) | (1<<1)); // Make sure the Mode registers are 00 for input
GPIOA->CRL &= ~((1<<2) | (1<<3)); // Set the CNF registers to 00 for input analog
} // End PinsConfig()
void delay(uint32_t delay) /* Psudo-delay in Milliseconds */
{
for(uint32_t i = 0; i <= delay; i++)
{
// Looping to delay!
}
}
Maybe below link is helpful for you:
stm32 dead lock

Interfacing ICM20948 with STM32F446RE HAL Layer in SPI

I am having troubles in interfacing the ICM20948 IMU with the HAL_layer of ST. My Master device (ST) is sending the data correctly to the slave (ICM) but the slave is not responding. I have checked very well every connection. I have tested several ICM's(3) and I have debugged it with my Logic analyser also (see pic below) I would really appreciate any help or pointer you could provide me.
My current setup is
The code its very simple I just have two simple read/write rotines
// --------------------------------------------------------------------------------------
/// \brief
///
/// \param *imu[in,out]: (IMU_def) IMU object with their respective ports
/// \param reg[in]: (uint8_t) register address
/// \param *pData[out]: (uint8_t) Data buffer
/// \return void
// --------------------------------------------------------------------------------------
void ICM_ReadOneByte (IMU_def *imu, uint8_t reg, uint8_t *pData)
{
reg = reg | 0x80; // Make the MSB active to tell is a read see p31
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_RESET); // Start transmission
HAL_Delay(1);
HAL_SPI_Transmit(imu->spi_bus, &reg, 1,1000);
while (HAL_SPI_GetState(imu->spi_bus) != HAL_SPI_STATE_READY) // TODO: Possible inf loop if slave don't answer. Counter?
;
HAL_SPI_Receive(imu->spi_bus, pData, 1,1000);
while (HAL_SPI_GetState(imu->spi_bus) != HAL_SPI_STATE_READY) // TODO: Possible inf loop if slave don't answer. Counter?
;
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_SET); // End transmission
}
// --------------------------------------------------------------------------------------
/// \brief
///
/// \param *imu[in,out]: (IMU_def) IMU object with their respective ports
/// \param reg[in]: (uint8_t) register address
/// \param Data[in]: (uint8_t) Data to write
/// \return void
// --------------------------------------------------------------------------------------
void ICM_WriteOneByte (IMU_def *imu, uint8_t reg, uint8_t Data)
{
reg = reg & 0x7F; // Make the MSB disable to tell is a write see p31
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_RESET); // Start transmission
HAL_Delay(5);
HAL_SPI_Transmit(imu->spi_bus, &reg, 1,1000);
HAL_SPI_Transmit(imu->spi_bus, &Data, 1,1000);
HAL_GPIO_WritePin(imu->CS_GPIO_Port, imu->CS_Pin, GPIO_PIN_SET); // End transmission
}
In the main function I use the SPI_HandleTypeDef hspi2; instance to initialise an IMU object as
imu.spi_bus = &hspi2;
imu.CS_GPIO_Port = GPIOB;
imu.CS_Pin = GPIO_PIN_4;
Just for testing that everything is fine I Just selected the BANK_0 and ask WHOIAM by
ICM_WriteOneByte(imu,USER_BANK_SEL, ICM_BANK_0); // USER_BANK_SEL (0x7F); USER_BANK_0:(0x00)
ICM_ReadOneByte(imu, 0x00, &whoami); //
I have also try several steps in between when before calling WHOIAM() such as setting the reseting the device, Seting the internal clock, etc but nothing works. This is how I set other lines just in case:
ICM_WriteOneByte(imu,PWR_MGMNT_1, PWR_MGMNT_1_DEV_RESET); //PWR_MGMNT_1 (0x06);PWR_MGMNT_1_DEV_RESET:(0x80)
ICM_WriteOneByte(imu,PWR_MGMNT_1,PWR_MGMNT_1_CLOCK_SEL_AUTO);//(0x01)
In addition I also try NSS Disable (as is only one device) or Hardware(ST as output) but nothing changed.
Here is a picture of my Logic analyser
As you can see The Master is sending correctly the data to the slave but the slave is always High in the MISO line. I checked the frequency with my logic analyser and is bellow 7MHz as stated in the datashet
Nfalling 8
Nrising 8
fmin 3.846 MHz
fmax 4.167 MHz
fmean 3.977 MHz
Any Ideas are very welcome.
Thanks!
From the manual:
NOTE: To prevent switching into I2C mode when using SPI, the I2C interface should be disabled by setting the I2C_IF_DIS configuration bit. Setting this bit should be performed immediately after waiting for the time specified by the “Start-Up Time for Register Read/Write” in Section 6.3.

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();
}
}

mbed not sleep with RTOS

I want to create a low power application with mbed (LPC1768) and have been following tutorial by Jim Hamblen at: https://mbed.org/cookbook/Power-Management and also http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/
I was able to wake the mbed from Sleep() by GPIO interrupt, UART interrupt, and Ticker. I use PowerControl library.
Here is my code:
#include "mbed.h"
#include "PowerControl/PowerControl.h"
#include "PowerControl/EthernetPowerControl.h"
// Need PowerControl *.h files from this URL
// http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/
// Function to power down magic USB interface chip with new firmware
#define USR_POWERDOWN (0x104)
int semihost_powerdown() {
uint32_t arg;
return __semihost(USR_POWERDOWN, &arg);
}
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);
bool rx_uart_irq = false;
Serial device(p28, p27); // tx, rx
InterruptIn button(p5);
// Circular buffers for serial TX and RX data - used by interrupt routines
const int buffer_size = 255;
// might need to increase buffer size for high baud rates
char tx_buffer[buffer_size];
char rx_buffer[buffer_size];
// Circular buffer pointers
// volatile makes read-modify-write atomic
volatile int tx_in=0;
volatile int tx_out=0;
volatile int rx_in=0;
volatile int rx_out=0;
// Line buffers for sprintf and sscanf
char tx_line[80];
char rx_line[80];
void Rx_interrupt();
void blink() {
myled2 = !myled2;
}
int main() {
//int result;
device.baud(9600);
device.attach(&Rx_interrupt, Serial::RxIrq);
// Normal mbed power level for this setup is around 690mW
// assuming 5V used on Vin pin
// If you don't need networking...
// Power down Ethernet interface - saves around 175mW
// Also need to unplug network cable - just a cable sucks power
PHY_PowerDown();
myled2 = 0;
// If you don't need the PC host USB interface....
// Power down magic USB interface chip - saves around 150mW
// Needs new firmware (URL below) and USB cable not connected
// http://mbed.org/users/simon/notebook/interface-powerdown/
// Supply power to mbed using Vin pin
//result = semihost_powerdown();
// Power consumption is now around half
// Turn off clock enables on unused I/O Peripherals (UARTs, Timers, PWM, SPI, CAN, I2C, A/D...)
// To save just a tiny bit more power - most are already off by default in this short code example
// See PowerControl.h for I/O device bit assignments
// Don't turn off GPIO - it is needed to blink the LEDs
Peripheral_PowerDown( ~( LPC1768_PCONP_PCUART0 |
LPC1768_PCONP_PCUART2 |
0));
// use Ticker interrupt and Sleep instead of a wait for time delay - saves up to 70mW
// Sleep halts and waits for an interrupt instead of executing instructions
// power is saved by not constantly fetching and decoding instructions
// Exact power level reduction depends on the amount of time spent in Sleep mode
//blinker.attach(&blink, 0.05);
//button.rise(&blink);
while (1) {
myled1 = 0;
printf("bye\n");
Sleep();
if(rx_uart_irq == true) {
printf("wake from uart irq\n");
}
myled1 = 1;
}
}
// Interupt Routine to read in data from serial port
void Rx_interrupt() {
myled2 = !myled2;
rx_uart_irq = true;
uint32_t IRR0= LPC_UART2->IIR;
while ((device.readable()) && (((rx_in + 1) % buffer_size) != rx_out)) {
rx_buffer[rx_in] = LPC_UART2->RBR;
rx_in = (rx_in + 1) % buffer_size;
}
}
Here is the problem: The Sleep() doesn't put the mbed to sleep when mbed-rtos library is added. Even when I don't use any function calls from the rtos library , Sleep() doesn't work.
My explanation: Probably the rtos has a timer running in the background and it generates an interrupt every now and then. (But it kinda doesn't make sense because I haven't use any function or object from rtos library)
My question:
Has any one made the Sleep() function work with rtos? if yes, please point me to the right direction or if you have the solution, please share.
I'm not sure if the Sleep() function is designed for RTOS use, but I doubt it. Someone with better knowledge in mbed-rtos could probably tell for sure, but I suspect that IRQ handling in the RTOS could cause the problem. If Sleep() relies on WFE then the MCU will sleep if there is no pending interrupt flag. In a super loop design you (should) have full control over this; with an RTOS you don't.
I suggest using Thread::wait() instead, which should have full knowledge about what the RTOS does. Can't tell if it causes a sleep, but I expect no less.
I used the following library once and it worked flawlessly. I am not sure if it would work with mbed 5 but its worth a try.
https://os.mbed.com/users/no2chem/code/PowerControl/