Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature stm32g4 can support #13565

Merged
merged 9 commits into from
Sep 17, 2020
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,14 @@ uint8_t SetSysClock_PLL_HSE(uint8_t bypass)
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
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;
#endif
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
Expand Down
2 changes: 1 addition & 1 deletion targets/TARGET_STM/TARGET_STM32G4/objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ struct analogin_s {

#if DEVICE_CAN
struct can_s {
CAN_HandleTypeDef CanHandle;
FDCAN_HandleTypeDef CanHandle;
int index;
int hz;
};
Expand Down
110 changes: 104 additions & 6 deletions targets/TARGET_STM/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
obj->index = 1;
}
#endif
#if defined(FDCAN3_BASE)
else if (pinmap->peripheral == CAN_3) {
obj->index = 2;
}
#endif
else {
error("can_init wrong instance\n");
Expand Down Expand Up @@ -118,24 +123,49 @@ 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>
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;
#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.Mode = FDCAN_MODE_NORMAL;
obj->CanHandle.Init.AutoRetransmission = ENABLE;
obj->CanHandle.Init.TransmitPause = DISABLE;
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.NominalTimeSeg2 = ntq - 1 - obj->CanHandle.Init.NominalTimeSeg1; // Phase_segment_2
obj->CanHandle.Init.NominalSyncJumpWidth = obj->CanHandle.Init.NominalTimeSeg2; // Synchronization_Jump_width
obj->CanHandle.Init.DataPrescaler = 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.DataTimeSeg2 = 0x1; // Not used - only in FDCAN
#ifndef TARGET_STM32G4
obj->CanHandle.Init.MessageRAMOffset = 0;
#endif
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
#ifndef TARGET_STM32G4
obj->CanHandle.Init.RxFifo0ElmtsNbr = 8;
obj->CanHandle.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
obj->CanHandle.Init.RxFifo1ElmtsNbr = 0;
Expand All @@ -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.TxBuffersNbr = 0;
obj->CanHandle.Init.TxFifoQueueElmtsNbr = 3;
#endif
obj->CanHandle.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
#ifndef TARGET_STM32G4
obj->CanHandle.Init.TxElmtSize = FDCAN_DATA_BYTES_8;

#endif
can_internal_init(obj);
}

Expand Down Expand Up @@ -194,11 +226,19 @@ void can_irq_free(can_t *obj)
HAL_NVIC_DisableIRQ(FDCAN2_IT0_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
else {
return;
}
#ifndef TARGET_STM32G4
HAL_NVIC_DisableIRQ(FDCAN_CAL_IRQn);
#endif
can_irq_ids[obj->index] = 0;
}

Expand Down Expand Up @@ -235,8 +275,34 @@ int can_frequency(can_t *obj, int f)
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;
#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.NominalTimeSeg2 = ntq - 1 - obj->CanHandle.Init.NominalTimeSeg1; // Phase_segment_2
obj->CanHandle.Init.NominalSyncJumpWidth = obj->CanHandle.Init.NominalTimeSeg2; // Synchronization_Jump_width
Expand Down Expand Up @@ -339,7 +405,7 @@ int can_read(can_t *obj, CAN_Message *msg, int handle)
msg->format = CANExtended;
}
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

return 1;
Expand Down Expand Up @@ -441,14 +507,21 @@ static void can_irq(CANName name, int id)
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_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);
}
}

#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_FLAG(&CanHandle, FDCAN_FLAG_ERROR_WARNING)) {
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_FLAG_ERROR_WARNING);
Expand Down Expand Up @@ -481,6 +554,7 @@ void FDCAN1_IT1_IRQHandler(void)
can_irq(CAN_1, 0);
}

#if defined(FDCAN2_BASE)
void FDCAN2_IT0_IRQHandler(void)
{
can_irq(CAN_2, 1);
Expand All @@ -490,6 +564,20 @@ void FDCAN2_IT1_IRQHandler(void)
{
can_irq(CAN_2, 1);
}
#endif //FDCAN2_BASE

#if defined(FDCAN3_BASE)
void FDCAN3_IT0_IRQHandler(void)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#if defined(FDCAN3_BASE) is missing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't add this line, since it was also missing for the FDCAN2 Handlers, which otherwise are also guarded with the #if defined(GDCAN2_BASE).

But I agree, it makes sense to add the guard for both the FDCAN2 and FDCAN3 Handlers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added guards in 35c9e7a

{
can_irq(CAN_3, 2);
}

void FDCAN3_IT1_IRQHandler(void)
{
can_irq(CAN_3, 2);
}
#endif //FDCAN3_BASE


// TODO Add other interrupts ?
void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
Expand All @@ -501,7 +589,11 @@ void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
interrupts = FDCAN_IT_TX_COMPLETE;
break;
case IRQ_RX:
#ifndef TARGET_STM32G4
interrupts = FDCAN_IT_RX_BUFFER_NEW_MESSAGE;
#else
interrupts = FDCAN_IT_RX_FIFO0_NEW_MESSAGE;
#endif
break;
case IRQ_ERROR:
interrupts = FDCAN_IT_ERROR_WARNING;
Expand Down Expand Up @@ -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_EnableIRQ(FDCAN2_IT1_IRQn);
#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 */
Expand Down
3 changes: 2 additions & 1 deletion targets/targets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2475,7 +2475,8 @@
"device_has_add": [
"ANALOGOUT",
"FLASH",
"MPU"
"MPU",
"CAN"
]
},
"NUCLEO_G474RE": {
Expand Down