126 lines
3.6 KiB
C
126 lines
3.6 KiB
C
![]() |
// SAE 2284-3 : minimum 16 tq, SJW 3, sample point at 81.3%
|
||
|
#define CAN_QUANTA 16U
|
||
|
#define CAN_SEQ1 12U
|
||
|
#define CAN_SEQ2 3U
|
||
|
#define CAN_SJW 3U
|
||
|
|
||
|
#define CAN_PCLK (CORE_FREQ / 2U / 1000U)
|
||
|
#define can_speed_to_prescaler(x) (CAN_PCLK / CAN_QUANTA * 10U / (x))
|
||
|
#define CAN_INIT_TIMEOUT_MS 500
|
||
|
|
||
|
bool llcan_set_speed(CAN_TypeDef *CAN_obj, uint32_t speed, bool loopback, bool silent) {
|
||
|
bool ret = true;
|
||
|
|
||
|
// initialization mode
|
||
|
CAN1->MCR = CAN_MCR_INRQ; // When we want to use only CAN2 - need to do that
|
||
|
CAN_obj->MCR = CAN_MCR_INRQ;
|
||
|
uint32_t timeout_counter = 0U;
|
||
|
while((CAN_obj->MSR & CAN_MSR_INAK) != CAN_MSR_INAK){
|
||
|
// Delay for about 1ms
|
||
|
delay(10000);
|
||
|
timeout_counter++;
|
||
|
|
||
|
if(timeout_counter >= CAN_INIT_TIMEOUT_MS){
|
||
|
ret = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(ret){
|
||
|
// set time quanta from defines
|
||
|
CAN_obj->BTR = ((CAN_BTR_TS1_0 * (CAN_SEQ1-1)) |
|
||
|
(CAN_BTR_TS2_0 * (CAN_SEQ2-1)) |
|
||
|
(CAN_BTR_SJW_0 * (CAN_SJW-1)) |
|
||
|
(can_speed_to_prescaler(speed) - 1U));
|
||
|
|
||
|
// silent loopback mode for debugging
|
||
|
if (loopback) {
|
||
|
CAN_obj->BTR |= CAN_BTR_SILM | CAN_BTR_LBKM;
|
||
|
}
|
||
|
if (silent) {
|
||
|
CAN_obj->BTR |= CAN_BTR_SILM;
|
||
|
}
|
||
|
|
||
|
CAN_obj->MCR |= CAN_MCR_AWUM; // Automatic wakeup mode
|
||
|
CAN_obj->MCR |= CAN_MCR_ABOM; // Automatic bus-off management
|
||
|
CAN_obj->MCR &= ~CAN_MCR_NART; // Automatic retransmission
|
||
|
CAN_obj->MCR |= CAN_MCR_TXFP; // Priority driven by the request order (chronologically)
|
||
|
CAN_obj->MCR &= ~CAN_MCR_INRQ;
|
||
|
|
||
|
timeout_counter = 0U;
|
||
|
while(((CAN_obj->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)) {
|
||
|
// Delay for about 1ms
|
||
|
delay(10000);
|
||
|
timeout_counter++;
|
||
|
|
||
|
if(timeout_counter >= CAN_INIT_TIMEOUT_MS){
|
||
|
ret = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
bool llcan_init(CAN_TypeDef *CAN_obj) {
|
||
|
bool ret = true;
|
||
|
|
||
|
// Enter init mode
|
||
|
CAN_obj->FMR |= CAN_FMR_FINIT;
|
||
|
|
||
|
// Wait for INAK bit to be set
|
||
|
uint32_t timeout_counter = 0U;
|
||
|
while(((CAN_obj->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)) {
|
||
|
// Delay for about 1ms
|
||
|
delay(10000);
|
||
|
timeout_counter++;
|
||
|
|
||
|
if(timeout_counter >= CAN_INIT_TIMEOUT_MS){
|
||
|
ret = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(ret){
|
||
|
// no mask
|
||
|
// For some weird reason some of these registers do not want to set properly on CAN2 and CAN3. Probably something to do with the single/dual mode and their different filters.
|
||
|
// Filters MUST be set always through CAN1(Master) as CAN2/3 are Slave
|
||
|
CAN1->sFilterRegister[0].FR1 = 0U;
|
||
|
CAN1->sFilterRegister[0].FR2 = 0U;
|
||
|
CAN1->sFilterRegister[14].FR1 = 0U;
|
||
|
CAN1->sFilterRegister[14].FR2 = 0U;
|
||
|
CAN1->FA1R |= 1U | (1U << 14);
|
||
|
|
||
|
// Exit init mode, do not wait
|
||
|
CAN_obj->FMR &= ~CAN_FMR_FINIT;
|
||
|
|
||
|
// enable certain CAN interrupts
|
||
|
CAN1->IER = 0U; // When we want to use only CAN2 - need to do that
|
||
|
CAN_obj->IER = CAN_IER_FMPIE0 | CAN_IER_TMEIE | CAN_IER_WKUIE;
|
||
|
|
||
|
if (CAN_obj == CAN1) {
|
||
|
HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
|
||
|
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0, 0);
|
||
|
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
|
||
|
HAL_NVIC_SetPriority(CAN1_SCE_IRQn, 0, 0);
|
||
|
HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn);
|
||
|
} else {
|
||
|
HAL_NVIC_SetPriority(CAN2_TX_IRQn, 0, 0);
|
||
|
HAL_NVIC_EnableIRQ(CAN2_TX_IRQn);
|
||
|
HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 0, 0);
|
||
|
HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn);
|
||
|
HAL_NVIC_SetPriority(CAN2_SCE_IRQn, 0, 0);
|
||
|
HAL_NVIC_EnableIRQ(CAN2_SCE_IRQn);
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void llcan_clear_send(CAN_TypeDef *CAN_obj) {
|
||
|
CAN_obj->TSR |= CAN_TSR_ABRQ0;
|
||
|
CAN_obj->MSR &= ~CAN_MSR_ERRI;
|
||
|
// cppcheck-suppress selfAssignment ; needed to clear the register
|
||
|
CAN_obj->MSR = CAN_obj->MSR;
|
||
|
}
|