I want my STMF103RE based system to sit in Stop Mode and then wake up when a CAN message arrives, do something about it, and go back to Stop Mode.
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?