AnsweredAssumed Answered

[STM32F4 Disco] Connect CAN 1 RX to EXTI 0

Question asked by Niko on Jul 23, 2014
Latest reply on Jul 24, 2014 by Clive One

*** please regard my update in my posting below ***

Hello,

I am facing a small problem at the moment. I set up a working CAN bus with 3 STM32F4.
One of the STM32F4 tells the two other ones via CAN to enter STOP-Mode. I have chosen the way via
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
as I need an interrupt to acour when one of the boards wake up again.
At the moment, I am able to wake up the boards via user pushbutton connected to EXTI 1 ( I
have remapped the user button to pin PA1 in order to keep EXTI 0 free for CAN).
Here is my code for entering STOP-Mode:

GPIO_InitTypeDef  GPIO_InitStructure;
  
// GPIOA and GPIOD are beeing used for the LEDs and the user pushbutton
// The other GPIOs are configured as Analog Input to save power in STOP-Mode
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB |
                    RCC_AHB1Periph_GPIOC |
                    RCC_AHB1Periph_GPIOE |
                    RCC_AHB1Periph_GPIOF |
                    RCC_AHB1Periph_GPIOG |
                    RCC_AHB1Periph_GPIOH |
                    RCC_AHB1Periph_GPIOI, ENABLE);
  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_Init(GPIOH, &GPIO_InitStructure);
GPIO_Init(GPIOI, &GPIO_InitStructure);
  
// GPIOs Periph clock disable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB |
                    RCC_AHB1Periph_GPIOC |
                    RCC_AHB1Periph_GPIOE |
                    RCC_AHB1Periph_GPIOF |
                    RCC_AHB1Periph_GPIOG |
                    RCC_AHB1Periph_GPIOH |
                    RCC_AHB1Periph_GPIOI, ENABLE);
  
PWR_WakeUpPinCmd(ENABLE);
  
// Diable Interrupts, otherwise STOP-Mode will not be entered
__disable_irq();
  
PWR_EnterSTOPMode(PWR_Regulator_LowPower,PWR_STOPEntry_WFI);
  
// Wait for interrupt - entering STOP-Mode at this point
__WFI();
  
// atfer leaving STOP-Mode...
PWR_WakeUpPinCmd(DISABLE);
  
__enable_irq();
  
// LEDs were blinking slower then before the STOP-Mode, so I used SystemInit to solve this problem
SystemInit();

This works fine so far. Here is how I connected the user pushbutton to EXTI 1:

GPIO_InitTypeDef   GPIO_InitStructure;
EXTI_InitTypeDef   EXTI_InitStructure;
NVIC_InitTypeDef   NVIC_InitStructure;
  
// Clock enable (GPIO)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  
// Configure as digital Input
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;            
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;           
GPIO_Init(GPIOA, &GPIO_InitStructure);
  
// Clock enable (SYSCONFIG)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  
// EXT_INT1 connect to Pin PA1
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource1);
  
// EXT_INT1 config
EXTI_InitStructure.EXTI_Line = EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
  
// NVIC config
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

And here the EXTI1_IRQHandler:

 

void EXTI1_IRQHandler(void)
{
  uint32_t wert;
  if(EXTI_GetITStatus(EXTI_Line1) != RESET)
  {
    EXTI_ClearITPendingBit(EXTI_Line1);
    DoSomething();
  }
}

 

The next step would be to wake up the boards through a CAN message. Herefore one of the boards (not in STOP-Mode) sends a "wakeup"-signal. I want the other two boards to wake up when they receive THIS message. The sleeping boards have CAN Filters, which only accept the messages, which are dedicated for them (I differ between the two boards, Slave 1 and Slave 2. So Slave 1 only gets the messages for Slave 1 and so on...). Is there a way, to connect the occuring interrupt behind the CAN filter to the EXTI 0 line? Or can I only connect the RX-Pin to EXTI 0?
If I could only connect the RX-Pin to EXTI 0, the boards would wake up with every CAN message passing the CAN bus... This is not what I want to achieve.

I tried to connect the RX-Pin to EXTI 0, but it did not work at all (disregarding the fact, that it would not fit my requirements, I did just want to try out if this works at all).

Here is the code for my CAN init at the moment (not connected to EXTI yet!!!):

// Init NVIC for CAN   
        
NVIC_InitTypeDef  NVIC_InitStructure;   
        
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
                          
// NVIC config   
      
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;                        
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;   
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   
NVIC_Init(&NVIC_InitStructure);   
        
        
// Init GPIO CAN   
        
GPIO_InitTypeDef  GPIO_InitStructure;   
        
// Clock Enable (GPIOD)   
RCC_AHB1PeriphClockCmd(GPIOD, ENABLE);   
        
        
// Connect CAN1 as alternate function   
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1);                     // TX   
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);                     // RX   
        
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;   
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;   
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;   
        
// TX-Pin   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;   
GPIO_Init(GPIOD, &GPIO_InitStructure);   
        
// RX-Pin   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;   
GPIO_Init(GPIOD, &GPIO_InitStructure);   
        
       
// Init CAN 
        
CAN_InitTypeDef        CAN_InitStructure;
CAN_FilterInitTypeDef  CAN_FilterInitStructure;
uint8_t n;
  
// CAN Clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
  
// CAN register init
CAN_DeInit(CAN1);
  
// CAN cell init
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
  
// CAN Baudrate [hier 125 kHz = 125 kBit/s]
CAN_InitStructure.CAN_BS1 = CAN_BS1_14tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_6tq;
CAN_InitStructure.CAN_Prescaler = CAN1_CLOCK_PRESCALER;
CAN_Init(CAN1, &CAN_InitStructure);
  
// CAN Filter 1 init
CAN_FilterInitStructure.CAN_FilterNumber = 0;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
// CAN ID (0x111 / 0x112) will be passed through
CAN_FilterInitStructure.CAN_FilterIdHigh = ((0x110 | SlaveType) << 5);
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
// CAN ID (0x11F) will be passed through
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (0x11F << 5);
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
  
// CAN Filter 2 init
CAN_FilterInitStructure.CAN_FilterNumber = 1;
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdList;
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
// CAN ID (0x121 / 0x122) will be passed through
CAN_FilterInitStructure.CAN_FilterIdHigh = ((0x120 | SlaveType) << 5);
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (0x12F << 5);
// CAN ID (0x12F) will be passed through  
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
  
// Init TX-Massage
CAN1_TxMessage.StdId = 0x00;
CAN1_TxMessage.ExtId = 0x00;
CAN1_TxMessage.RTR = CAN_RTR_DATA;
CAN1_TxMessage.IDE = CAN_ID_STD;
CAN1_TxMessage.DLC = 0;
  
// Init RX-Massage
CAN1_RxMessage.StdId = 0x00;
CAN1_RxMessage.ExtId = 0x00;
CAN1_RxMessage.IDE = CAN_ID_STD;
CAN1_RxMessage.DLC = 0;
CAN1_RxMessage.FMI = 0;
  
for(n=0;n<8;n++)
{
    CAN1_RxMessage.Data[n] = 0x00;
    CAN1_TxMessage.Data[n] = 0x00;
}
  
// Enable Interrupt
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

 

So at the moment, CAN messages will be handled by an interrupt:

void CAN1_RX0_IRQHandler(void)

I want to leave the way messages are handled like this, the only thing I would like to change, is that I need an EXTI in case of a CAN message coming in. THE MCU would then wake up from STOP-Mode.

Here is how I thought it would work, but it did not...
[Changes to CAN Init]

// Init NVIC for CAN  
      
NVIC_InitTypeDef  NVIC_InitStructure;  
      
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;                  // Added this for EXTI CAN 
                        
// NVIC config  
    
// which priority should I choose??? Do I need to regard the EXTI 1 priority? 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0;                       
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;  
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
NVIC_Init(&NVIC_InitStructure);  
      
      
// Init GPIO CAN  
      
GPIO_InitTypeDef  GPIO_InitStructure;  
EXTI_InitTypeDef   EXTI_InitStructure;                             // added this for EXTI CAN 
      
// Clock Enable (GPIOD)  
RCC_AHB1PeriphClockCmd(GPIOD, ENABLE);  
      
      
// Connect CAN1 as alternate function  
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1);                     // TX  
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);                     // RX  
      
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  
GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;  
      
// TX-Pin  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;  
GPIO_Init(GPIOD, &GPIO_InitStructure);  
      
// RX-Pin  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;  
GPIO_Init(GPIOD, &GPIO_InitStructure);  
      
    
// Added this for EXTI CAN: 
    
// Clock enable (SYSCONFIG) 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); 
    
// EXT_INT0 connect to Pin0 [GPIOD] = RX-PIN 
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, GPIO_Pin_0); 
    
// EXT_INT0 config 
EXTI_InitStructure.EXTI_Line = EXTI_Line0; 
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; 
EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
EXTI_Init(&EXTI_InitStructure); 
    
    
      
// Init CAN did not change, BUT... do I need to change anything with the interrupt, that I am enabling in "Init CAN"?: 
      
// Enable Interrupt  
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

And changes to the ISR for incoming CAN messages:

void EXTI0_IRQHandler(void)
{
      if(EXTI_GetITStatus(EXTI_Line0) != RESET)
      {
             EXTI_ClearITPendingBit(EXTI_Line0);
             CAN_Receive(CAN1, CAN_FIFO0, &CAN1_RxMessage);
             DoSomething();
      }
}

Do I need to activate the CAN Clock for the STOP-Mode? In the reference manual on page 252, they tell something about a:

RCC APB1 peripheral clock enable in low power mode register

I am not quite sure, if the APB1 peripheral clock is deactivated during STOP-Mode...

 

 

In case that there is no chance to deal with this problem via EXTI, what about these two ideas:

1.)
There is an automatic wakeup Mode through CAN bus activity detection, which throws an interrupt. Could one connect this interrupt to an EXTI line? (Ref. Manual page 1063, Sleep Mode CAN) As soon, as the MCU is in RUN Mode, CAN messages would be received via interrupt. The "Wakeup-interrupt" would only occour once to wake up the MCU.

2.)

I tried to enable the STOP-Mode via WFE, but the MCU did not enter the STOP-Mode. I tried the sequence:

SEV;
WFE;
WFE;

as the firtst WFE clears the event register and the second WFE should put the MCU into STOP-Mode... but it did not work.
If it would work, there would be no ISR to handle, just the MCU waking up and going back to normal RUN-Mode, where CAN messages are handled via interrupt.

Thanks so far,

kind regards,

Niko

Outcomes