2021-10-12 09:47 PM
I want my system to sit in Stop Mode and then wake up and receive and process a CAN message when one arrives.
The code I generated for setting up the system includes:
RCC->APB1ENR |= ( 1UL << 25); /* enable clock for CAN -- Note: MCBSTM32 uses PB8 and PB9 for CAN */
RCC->APB2ENR |= ( 1UL << 0); /* enable clock for AF */
AFIO->MAPR &= 0xFFFF9FFF; /* reset CAN remap */
AFIO->MAPR |= 0x00004000; /* Set CAN remap, use PB8, PB9 */
RCC->APB2ENR |= ( 1UL << 3); /* enable clock for GPIO B */
GPIOB->CRH &= ~(0x000000FF);
GPIOB->CRH |= (0x000000B8); /* CAN RX PB.8 input push pull, CAN TX PB.9 alt.output push pull*/
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); /* enable CAN RX interrupt */
*(unsigned long *) EXTI_EMR |= 0x00000100; // If PB8 is used as an EXTI, it generates an EXTI5_9 interrupt, so unmask MR8 in the Interrupt Mask Register
*(unsigned long *) EXTI_FTSR |= 0x00000100; // Enables a falling trigger to cause an Event or an Interrupt for EXTI8
*(unsigned long *) AFIO_EXTICR3 &= 0xFFFFFFF0; // Set EXTI8 to PB8 (PB8 is wired to CAN_RXD)
*(unsigned long *) AFIO_EXTICR3 |= 0x00000001;
// So PB8 is set up as both RXD for the CAN, and also as EXTI8 to wake up out of Stop Mode
Then to go into Stop Mode:
NVIC_DisableIRQ(TIM1_UP_IRQn); // Disable the TIMER interrupt (which does some stuff to process CAN messages)
*(unsigned long *) EXTI_PR = 0x0007FFFF; // Clear all pending external interrupts
SAVE_REGS(); // Save the GPBIO_B and the RCC register contents
*(unsigned long *) GPIOB_ODR &= 0xFFDF; // Set PB5 (switch enable) low. This disables the motor switches.
*(unsigned long *) GPIOB_ODR &= 0xFBFF; // Set PB10 low to keep the CAN transceiver in normal mode. Don't actually need to do this; it is already done.
*(unsigned long *) RCC_APB2ENR = 0x00000009; // Turn on clocks to AFIOEN (bit0) and IOPB (bit3) only;
*(unsigned long *) RCC_APB1ENR = 0x02000000; // Turn on CAN clock. Not actually needed; this was done in CAN_Init and we never turned it off
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); // Enable the CAN receive interrupt USB_LP_CAN1_RX0_IRQn; also not needed. Already done in CAN_Init.
NVIC_EnableIRQ(EXTI9_5_IRQn); // EXTI9_5_IRQn is the interrupt for EXTI8 -- Seems to wake from Stop Mode whether or not the ISR is enabled
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // Doing it with PWR_Regulator_On doesn't seem to make any difference.
So I have setup PB8 to be both the RXD for the CAN, and also to be EXTI8. That seems to work perfectly OK . Then we also have just the clocks for AFIOEN, and IOPB, and for the CAN enabled. The CAN transceiver is a MAX3051, and it is always left in the fully active mode so that PB8 which is connected to RXD will always get a correct level reflecting whether the CAN bus is dominant or recessive. When it gets to the PWR_EnterSTOPMode instruction, the processor goes into Stop Mode as it should and power falls to ~20 mW, as it should.
When a CAN message appears on the bus, what actually happens is that the first message wakes it up but is NOT received or acted on by the program, but after that any following messages are received and acted on properly. What I want, of course is to have the first CAN message which wakes it up also be received by the program like any other CAN message.
Is there a clock or register value which has to be set to make this work? Is what I am trying to do even possible?
2021-10-13 09:01 AM
You need HSI RC wakeup time + regulator wakeup time from Low-power mode to wake up, and so probably some part of the CAN message is already lost.
2021-10-13 11:30 AM
2021-10-13 01:12 PM
I'm new to this forum, and this is my first post, so please excuse my newbieness.
Uwe Bonnes suggests that since it takes some time for the processor to get up and running, that some part of the CAN message has already gone by, so that the full message is not available to the software.
This is what I don't understand. I thought the CAN engine was purely hardware and that an incoming CAN message would be filtered, checked for CRC, etc., and then the message contents transferred to a structure of some sort called CAN_RxMsg, and THEN the CAN interrupt would be raised to tell the software to go and get it. If this were the case, the processor could take its sweet time to get going after wake up, and when it finally did the CAN message would still be sitting there waiting to be picked up. I was thinking that there was something more I had to do to keep the CAN hardware fully operational while in Stop Mode. Like maybe some clock that I didn't have enabled. (In my current code I have the CAN clock in APB1ENR and the AFIO and GPIOB clocks in APB2ENR enabled. Is there something more that the CAN hardware needs?)
Or is it the case that in the STM32F103 the CAN receipt is not a purely hardware function and it actually needs the processor running to capture a CAN message?
I think Andrew Neil was telling me that I shouldn't put a bunch of code into the body of my question, but that I should rather use the Code Snippet button. Is that correct? I will try to do it correctly next time!
-- Henry Heetderks
2021-10-13 03:26 PM
"I think Andrew Neil was telling me that I shouldn't put a bunch of code into the body of my question, but that I should rather use the Code Snippet button. Is that correct?"
Yes.
That way it gets properly formatted - doesn't lose indentation, etc.
This is common to (pretty much) all internet forums: https://www.avrfreaks.net/comment/2477336#comment-2477336
2021-10-13 03:50 PM
Thank you, Andrew. This is my first foray onto a forum.
2021-10-14 01:51 AM
To save current, a lot of clocks are switched off in Stop. So is the CAN clock. So either use some pre-alert or a normal sleep. In general, only some GPIO and low-power devices like LPUART are available in stop mode.