Merge pull request #13565 from m-ecry/feature-stm32g4-can-support

Feature stm32g4 can support
pull/13548/head
Martin Kojtal 2020-09-17 15:08:46 +01:00 committed by GitHub
commit 75544a7ce0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 114 additions and 8 deletions

View File

@ -105,7 +105,14 @@ uint8_t SetSysClock_PLL_HSE(uint8_t bypass)
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV6; RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV6;
//! 170MHz as a core frequency for FDCAN is not suitable for many frequencies,
//! as it provides low accuracy. When no FDCAN is used, the full capacity of 170 MHz
//! should be standard.
#if DEVICE_CAN
RCC_OscInitStruct.PLL.PLLN = 80;
#else
RCC_OscInitStruct.PLL.PLLN = 85; RCC_OscInitStruct.PLL.PLLN = 85;
#endif
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;

View File

@ -133,7 +133,7 @@ struct analogin_s {
#if DEVICE_CAN #if DEVICE_CAN
struct can_s { struct can_s {
CAN_HandleTypeDef CanHandle; FDCAN_HandleTypeDef CanHandle;
int index; int index;
int hz; int hz;
}; };

View File

@ -76,6 +76,11 @@ static void _can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz
else if (pinmap->peripheral == CAN_2) { else if (pinmap->peripheral == CAN_2) {
obj->index = 1; obj->index = 1;
} }
#endif
#if defined(FDCAN3_BASE)
else if (pinmap->peripheral == CAN_3) {
obj->index = 2;
}
#endif #endif
else { else {
error("can_init wrong instance\n"); error("can_init wrong instance\n");
@ -118,14 +123,36 @@ static void _can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz
Phase_segment_2 | 30 tq | <nts2> = <n_tq> - 1 - <nts1> Phase_segment_2 | 30 tq | <nts2> = <n_tq> - 1 - <nts1>
Synchronization_Jump_width | 30 tq | <nsjw> = <nts2> Synchronization_Jump_width | 30 tq | <nsjw> = <nts2>
*/ */
// !Attention Not all bitrates can be covered with all fdcan-core-clk values. When a clk
// does not work for the desired bitrate, change system_clock settings for FDCAN_CLK
// (default FDCAN_CLK is PLLQ)
#ifdef TARGET_STM32G4
int ntq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_FDCAN) / hz;
#else
// STM32H7 doesn't support yet HAL_RCCEx_GetPeriphCLKFreq for FDCAN
// Internal ST ticket 92465
int ntq = 10000000 / hz; int ntq = 10000000 / hz;
#endif
int nominalPrescaler = 1;
// !When the sample point should be lower than 50%, this must be changed to
// !IS_FDCAN_NOMINAL_TSEG2(ntq/nominalPrescaler), since
// NTSEG2 and SJW max values are lower. For now the sample point is fix @75%
while (!IS_FDCAN_NOMINAL_TSEG1(ntq/nominalPrescaler)){
nominalPrescaler ++;
if (!IS_FDCAN_NOMINAL_PRESCALER(nominalPrescaler)){
error("Could not determine good nominalPrescaler. Bad clock value\n");
}
}
ntq = ntq/nominalPrescaler;
obj->CanHandle.Init.FrameFormat = FDCAN_FRAME_CLASSIC; obj->CanHandle.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
obj->CanHandle.Init.Mode = FDCAN_MODE_NORMAL; obj->CanHandle.Init.Mode = FDCAN_MODE_NORMAL;
obj->CanHandle.Init.AutoRetransmission = ENABLE; obj->CanHandle.Init.AutoRetransmission = ENABLE;
obj->CanHandle.Init.TransmitPause = DISABLE; obj->CanHandle.Init.TransmitPause = DISABLE;
obj->CanHandle.Init.ProtocolException = ENABLE; obj->CanHandle.Init.ProtocolException = ENABLE;
obj->CanHandle.Init.NominalPrescaler = 1; // Prescaler obj->CanHandle.Init.NominalPrescaler = nominalPrescaler; // Prescaler
obj->CanHandle.Init.NominalTimeSeg1 = ntq * 0.75; // Phase_segment_1 obj->CanHandle.Init.NominalTimeSeg1 = ntq * 0.75; // Phase_segment_1
obj->CanHandle.Init.NominalTimeSeg2 = ntq - 1 - obj->CanHandle.Init.NominalTimeSeg1; // Phase_segment_2 obj->CanHandle.Init.NominalTimeSeg2 = ntq - 1 - obj->CanHandle.Init.NominalTimeSeg1; // Phase_segment_2
obj->CanHandle.Init.NominalSyncJumpWidth = obj->CanHandle.Init.NominalTimeSeg2; // Synchronization_Jump_width obj->CanHandle.Init.NominalSyncJumpWidth = obj->CanHandle.Init.NominalTimeSeg2; // Synchronization_Jump_width
@ -133,9 +160,12 @@ static void _can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz
obj->CanHandle.Init.DataSyncJumpWidth = 0x1; // Not used - only in FDCAN obj->CanHandle.Init.DataSyncJumpWidth = 0x1; // Not used - only in FDCAN
obj->CanHandle.Init.DataTimeSeg1 = 0x1; // Not used - only in FDCAN obj->CanHandle.Init.DataTimeSeg1 = 0x1; // Not used - only in FDCAN
obj->CanHandle.Init.DataTimeSeg2 = 0x1; // Not used - only in FDCAN obj->CanHandle.Init.DataTimeSeg2 = 0x1; // Not used - only in FDCAN
#ifndef TARGET_STM32G4
obj->CanHandle.Init.MessageRAMOffset = 0; obj->CanHandle.Init.MessageRAMOffset = 0;
#endif
obj->CanHandle.Init.StdFiltersNbr = 1; // to be aligned with the handle parameter in can_filter obj->CanHandle.Init.StdFiltersNbr = 1; // to be aligned with the handle parameter in can_filter
obj->CanHandle.Init.ExtFiltersNbr = 1; // to be aligned with the handle parameter in can_filter obj->CanHandle.Init.ExtFiltersNbr = 1; // to be aligned with the handle parameter in can_filter
#ifndef TARGET_STM32G4
obj->CanHandle.Init.RxFifo0ElmtsNbr = 8; obj->CanHandle.Init.RxFifo0ElmtsNbr = 8;
obj->CanHandle.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8; obj->CanHandle.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
obj->CanHandle.Init.RxFifo1ElmtsNbr = 0; obj->CanHandle.Init.RxFifo1ElmtsNbr = 0;
@ -145,9 +175,11 @@ static void _can_init_freq_direct(can_t *obj, const can_pinmap_t *pinmap, int hz
obj->CanHandle.Init.TxEventsNbr = 3; obj->CanHandle.Init.TxEventsNbr = 3;
obj->CanHandle.Init.TxBuffersNbr = 0; obj->CanHandle.Init.TxBuffersNbr = 0;
obj->CanHandle.Init.TxFifoQueueElmtsNbr = 3; obj->CanHandle.Init.TxFifoQueueElmtsNbr = 3;
#endif
obj->CanHandle.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION; obj->CanHandle.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
#ifndef TARGET_STM32G4
obj->CanHandle.Init.TxElmtSize = FDCAN_DATA_BYTES_8; obj->CanHandle.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
#endif
can_internal_init(obj); can_internal_init(obj);
} }
@ -194,11 +226,19 @@ void can_irq_free(can_t *obj)
HAL_NVIC_DisableIRQ(FDCAN2_IT0_IRQn); HAL_NVIC_DisableIRQ(FDCAN2_IT0_IRQn);
HAL_NVIC_DisableIRQ(FDCAN2_IT1_IRQn); HAL_NVIC_DisableIRQ(FDCAN2_IT1_IRQn);
} }
#endif
#if defined(FDCAN3_BASE)
else if (can == CAN_3) {
HAL_NVIC_DisableIRQ(FDCAN3_IT0_IRQn);
HAL_NVIC_DisableIRQ(FDCAN3_IT1_IRQn);
}
#endif #endif
else { else {
return; return;
} }
#ifndef TARGET_STM32G4
HAL_NVIC_DisableIRQ(FDCAN_CAL_IRQn); HAL_NVIC_DisableIRQ(FDCAN_CAL_IRQn);
#endif
can_irq_ids[obj->index] = 0; can_irq_ids[obj->index] = 0;
} }
@ -235,8 +275,34 @@ int can_frequency(can_t *obj, int f)
error("HAL_FDCAN_Stop error\n"); error("HAL_FDCAN_Stop error\n");
} }
/* See can_init_freq function for calculation details */
/* See can_init_freq function for calculation details
*
* !Attention Not all bitrates can be covered with all fdcan-core-clk values. When a clk
* does not work for the desired bitrate, change system_clock settings for FDCAN_CLK
* (default FDCAN_CLK is PLLQ)
*/
#ifdef TARGET_STM32G4
int ntq = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_FDCAN) / f;
#else
// STM32H7 doesn't support yet HAL_RCCEx_GetPeriphCLKFreq for FDCAN
// Internal ST ticket 92465
int ntq = 10000000 / f; int ntq = 10000000 / f;
#endif
int nominalPrescaler = 1;
// !When the sample point should be lower than 50%, this must be changed to
// !IS_FDCAN_DATA_TSEG2(ntq/nominalPrescaler), since
// NTSEG2 and SJW max values are lower. For now the sample point is fix @75%
while (!IS_FDCAN_DATA_TSEG1(ntq/nominalPrescaler)){
nominalPrescaler ++;
if (!IS_FDCAN_NOMINAL_PRESCALER(nominalPrescaler)){
error("Could not determine good nominalPrescaler. Bad clock value\n");
}
}
ntq = ntq/nominalPrescaler;
obj->CanHandle.Init.NominalPrescaler = nominalPrescaler;
obj->CanHandle.Init.NominalTimeSeg1 = ntq * 0.75; // Phase_segment_1 obj->CanHandle.Init.NominalTimeSeg1 = ntq * 0.75; // Phase_segment_1
obj->CanHandle.Init.NominalTimeSeg2 = ntq - 1 - obj->CanHandle.Init.NominalTimeSeg1; // Phase_segment_2 obj->CanHandle.Init.NominalTimeSeg2 = ntq - 1 - obj->CanHandle.Init.NominalTimeSeg1; // Phase_segment_2
obj->CanHandle.Init.NominalSyncJumpWidth = obj->CanHandle.Init.NominalTimeSeg2; // Synchronization_Jump_width obj->CanHandle.Init.NominalSyncJumpWidth = obj->CanHandle.Init.NominalTimeSeg2; // Synchronization_Jump_width
@ -339,7 +405,7 @@ int can_read(can_t *obj, CAN_Message *msg, int handle)
msg->format = CANExtended; msg->format = CANExtended;
} }
msg->id = RxHeader.Identifier; msg->id = RxHeader.Identifier;
msg->type = CANData; msg->type = (RxHeader.RxFrameType == FDCAN_DATA_FRAME) ? CANData : CANRemote;
msg->len = RxHeader.DataLength >> 16; // see FDCAN_data_length_code value msg->len = RxHeader.DataLength >> 16; // see FDCAN_data_length_code value
return 1; return 1;
@ -441,14 +507,21 @@ static void can_irq(CANName name, int id)
irq_handler(can_irq_ids[id], IRQ_TX); irq_handler(can_irq_ids[id], IRQ_TX);
} }
} }
#ifndef TARGET_STM32G4
if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_RX_BUFFER_NEW_MESSAGE)) { if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_RX_BUFFER_NEW_MESSAGE)) {
if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_IT_RX_BUFFER_NEW_MESSAGE)) { if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_IT_RX_BUFFER_NEW_MESSAGE)) {
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_IT_RX_BUFFER_NEW_MESSAGE); __HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_IT_RX_BUFFER_NEW_MESSAGE);
irq_handler(can_irq_ids[id], IRQ_RX); irq_handler(can_irq_ids[id], IRQ_RX);
} }
} }
#else
if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE)) {
if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE)) {
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_IT_RX_FIFO0_NEW_MESSAGE);
irq_handler(can_irq_ids[id], IRQ_RX);
}
}
#endif
if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_ERROR_WARNING)) { if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_ERROR_WARNING)) {
if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_FLAG_ERROR_WARNING)) { if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_FLAG_ERROR_WARNING)) {
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_FLAG_ERROR_WARNING); __HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_FLAG_ERROR_WARNING);
@ -481,6 +554,7 @@ void FDCAN1_IT1_IRQHandler(void)
can_irq(CAN_1, 0); can_irq(CAN_1, 0);
} }
#if defined(FDCAN2_BASE)
void FDCAN2_IT0_IRQHandler(void) void FDCAN2_IT0_IRQHandler(void)
{ {
can_irq(CAN_2, 1); can_irq(CAN_2, 1);
@ -490,6 +564,20 @@ void FDCAN2_IT1_IRQHandler(void)
{ {
can_irq(CAN_2, 1); can_irq(CAN_2, 1);
} }
#endif //FDCAN2_BASE
#if defined(FDCAN3_BASE)
void FDCAN3_IT0_IRQHandler(void)
{
can_irq(CAN_3, 2);
}
void FDCAN3_IT1_IRQHandler(void)
{
can_irq(CAN_3, 2);
}
#endif //FDCAN3_BASE
// TODO Add other interrupts ? // TODO Add other interrupts ?
void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable) void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
@ -501,7 +589,11 @@ void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
interrupts = FDCAN_IT_TX_COMPLETE; interrupts = FDCAN_IT_TX_COMPLETE;
break; break;
case IRQ_RX: case IRQ_RX:
#ifndef TARGET_STM32G4
interrupts = FDCAN_IT_RX_BUFFER_NEW_MESSAGE; interrupts = FDCAN_IT_RX_BUFFER_NEW_MESSAGE;
#else
interrupts = FDCAN_IT_RX_FIFO0_NEW_MESSAGE;
#endif
break; break;
case IRQ_ERROR: case IRQ_ERROR:
interrupts = FDCAN_IT_ERROR_WARNING; interrupts = FDCAN_IT_ERROR_WARNING;
@ -531,6 +623,12 @@ void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
NVIC_SetVector(FDCAN2_IT1_IRQn, (uint32_t)&FDCAN2_IT1_IRQHandler); NVIC_SetVector(FDCAN2_IT1_IRQn, (uint32_t)&FDCAN2_IT1_IRQHandler);
NVIC_EnableIRQ(FDCAN2_IT1_IRQn); NVIC_EnableIRQ(FDCAN2_IT1_IRQn);
#endif #endif
#if defined(FDCAN3_BASE)
NVIC_SetVector(FDCAN3_IT0_IRQn, (uint32_t)&FDCAN3_IT0_IRQHandler);
NVIC_EnableIRQ(FDCAN3_IT0_IRQn);
NVIC_SetVector(FDCAN3_IT1_IRQn, (uint32_t)&FDCAN3_IT1_IRQHandler);
NVIC_EnableIRQ(FDCAN3_IT1_IRQn);
#endif
} }
#else /* FDCAN1 */ #else /* FDCAN1 */

View File

@ -2467,7 +2467,8 @@
"device_has_add": [ "device_has_add": [
"ANALOGOUT", "ANALOGOUT",
"FLASH", "FLASH",
"MPU" "MPU",
"CAN"
] ]
}, },
"NUCLEO_G474RE": { "NUCLEO_G474RE": {