mirror of https://github.com/ARMmbed/mbed-os.git
commit
c7679109ef
|
@ -127,10 +127,10 @@ uint8_t SetSysClock_PLL_HSE(uint8_t bypass)
|
||||||
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
|
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
|
||||||
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 = 4;
|
RCC_OscInitStruct.PLL.PLLM = 4; // 2 MHz
|
||||||
RCC_OscInitStruct.PLL.PLLN = 400;
|
RCC_OscInitStruct.PLL.PLLN = 400; // 800 MHz
|
||||||
RCC_OscInitStruct.PLL.PLLP = 2;
|
RCC_OscInitStruct.PLL.PLLP = 2; // PLLCLK = SYSCLK = 400 MHz
|
||||||
RCC_OscInitStruct.PLL.PLLQ = 32;
|
RCC_OscInitStruct.PLL.PLLQ = 80; // PLL1Q used for FDCAN = 10 MHz
|
||||||
RCC_OscInitStruct.PLL.PLLR = 2;
|
RCC_OscInitStruct.PLL.PLLR = 2;
|
||||||
RCC_OscInitStruct.PLL.PLLFRACN = 0;
|
RCC_OscInitStruct.PLL.PLLFRACN = 0;
|
||||||
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
|
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-2017 ARM Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#ifndef MBED_CAN_DEVICE_H
|
|
||||||
#define MBED_CAN_DEVICE_H
|
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "stm32h7xx.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if DEVICE_CAN
|
|
||||||
|
|
||||||
#if defined(CAN3_BASE)
|
|
||||||
|
|
||||||
#define CAN_NUM 3 // Number of CAN peripherals present in the STM32 serie
|
|
||||||
|
|
||||||
#define CAN3_IRQ_RX_IRQN CAN3_RX0_IRQn
|
|
||||||
#define CAN3_IRQ_RX_VECT CAN3_RX0_IRQHandler
|
|
||||||
#define CAN3_IRQ_TX_IRQN CAN3_TX_IRQn
|
|
||||||
#define CAN3_IRQ_TX_VECT CAN3_TX_IRQHandler
|
|
||||||
#define CAN3_IRQ_ERROR_IRQN CAN3_SCE_IRQn
|
|
||||||
#define CAN3_IRQ_ERROR_VECT CAN3_SCE_IRQHandler
|
|
||||||
#define CAN3_IRQ_PASSIVE_IRQN CAN3_SCE_IRQn
|
|
||||||
#define CAN3_IRQ_PASSIVE_VECT CAN3_SCE_IRQHandler
|
|
||||||
#define CAN3_IRQ_BUS_IRQN CAN3_SCE_IRQn
|
|
||||||
#define CAN3_IRQ_BUS_VECT CAN3_SCE_IRQHandler
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define CAN_NUM 2 // Number of CAN peripherals present in the STM32 serie
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CAN1_IRQ_RX_IRQN CAN1_RX0_IRQn
|
|
||||||
#define CAN1_IRQ_RX_VECT CAN1_RX0_IRQHandler
|
|
||||||
#define CAN1_IRQ_TX_IRQN CAN1_TX_IRQn
|
|
||||||
#define CAN1_IRQ_TX_VECT CAN1_TX_IRQHandler
|
|
||||||
#define CAN1_IRQ_ERROR_IRQN CAN1_SCE_IRQn
|
|
||||||
#define CAN1_IRQ_ERROR_VECT CAN1_SCE_IRQHandler
|
|
||||||
#define CAN1_IRQ_PASSIVE_IRQN CAN1_SCE_IRQn
|
|
||||||
#define CAN1_IRQ_PASSIVE_VECT CAN1_SCE_IRQHandler
|
|
||||||
#define CAN1_IRQ_BUS_IRQN CAN1_SCE_IRQn
|
|
||||||
#define CAN1_IRQ_BUS_VECT CAN1_SCE_IRQHandler
|
|
||||||
|
|
||||||
#define CAN2_IRQ_RX_IRQN CAN2_RX0_IRQn
|
|
||||||
#define CAN2_IRQ_RX_VECT CAN2_RX0_IRQHandler
|
|
||||||
#define CAN2_IRQ_TX_IRQN CAN2_TX_IRQn
|
|
||||||
#define CAN2_IRQ_TX_VECT CAN2_TX_IRQHandler
|
|
||||||
#define CAN2_IRQ_ERROR_IRQN CAN2_SCE_IRQn
|
|
||||||
#define CAN2_IRQ_ERROR_VECT CAN2_SCE_IRQHandler
|
|
||||||
#define CAN2_IRQ_PASSIVE_IRQN CAN2_SCE_IRQn
|
|
||||||
#define CAN2_IRQ_PASSIVE_VECT CAN2_SCE_IRQHandler
|
|
||||||
#define CAN2_IRQ_BUS_IRQN CAN2_SCE_IRQn
|
|
||||||
#define CAN2_IRQ_BUS_VECT CAN2_SCE_IRQHandler
|
|
||||||
|
|
||||||
#endif // DEVICE_CAN
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -17,6 +17,495 @@
|
||||||
|
|
||||||
#if DEVICE_CAN
|
#if DEVICE_CAN
|
||||||
|
|
||||||
|
#ifdef FDCAN1
|
||||||
|
|
||||||
|
#include "pinmap.h"
|
||||||
|
#include "PeripheralPins.h"
|
||||||
|
#include "mbed_error.h"
|
||||||
|
|
||||||
|
static uint32_t can_irq_ids[2] = {0};
|
||||||
|
static can_irq_handler irq_handler;
|
||||||
|
|
||||||
|
/** Call all the init functions
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* 0 if mode change failed or unsupported,
|
||||||
|
* 1 if mode change was successful
|
||||||
|
*/
|
||||||
|
int can_internal_init(can_t *obj)
|
||||||
|
{
|
||||||
|
if (HAL_FDCAN_Init(&obj->CanHandle) != HAL_OK) {
|
||||||
|
error("HAL_FDCAN_Init error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_filter(obj, 0, 0, CANStandard, 0) == 0) {
|
||||||
|
error("can_filter error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_filter(obj, 0, 0, CANExtended, 0) == 0) {
|
||||||
|
error("can_filter error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_FDCAN_ConfigGlobalFilter(&obj->CanHandle, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK) {
|
||||||
|
error("HAL_FDCAN_ConfigGlobalFilter error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_FDCAN_Start(&obj->CanHandle) != HAL_OK) {
|
||||||
|
error("HAL_FDCAN_Start error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_init(can_t *obj, PinName rd, PinName td)
|
||||||
|
{
|
||||||
|
/* default frequency is 100 kHz */
|
||||||
|
can_init_freq(obj, rd, td, 100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void can_init_freq(can_t *obj, PinName rd, PinName td, int hz)
|
||||||
|
{
|
||||||
|
CANName can_rd = (CANName)pinmap_peripheral(rd, PinMap_CAN_RD);
|
||||||
|
CANName can_td = (CANName)pinmap_peripheral(td, PinMap_CAN_TD);
|
||||||
|
CANName can = (CANName)pinmap_merge(can_rd, can_td);
|
||||||
|
MBED_ASSERT((int)can != NC);
|
||||||
|
|
||||||
|
__HAL_RCC_FDCAN_CLK_ENABLE();
|
||||||
|
|
||||||
|
if (can == CAN_1) {
|
||||||
|
obj->index = 0;
|
||||||
|
}
|
||||||
|
#if defined(FDCAN2_BASE)
|
||||||
|
else if (can == CAN_2) {
|
||||||
|
obj->index = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
error("can_init wrong instance\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select PLL1Q as source of FDCAN clock
|
||||||
|
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
|
||||||
|
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
|
||||||
|
RCC_PeriphClkInit.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL; // 10 MHz (RCC_OscInitStruct.PLL.PLLQ = 80)
|
||||||
|
if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit) != HAL_OK) {
|
||||||
|
error("HAL_RCCEx_PeriphCLKConfig error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure CAN pins
|
||||||
|
pinmap_pinout(rd, PinMap_CAN_RD);
|
||||||
|
pinmap_pinout(td, PinMap_CAN_TD);
|
||||||
|
// Add pull-ups
|
||||||
|
if (rd != NC) {
|
||||||
|
pin_mode(rd, PullUp);
|
||||||
|
}
|
||||||
|
if (td != NC) {
|
||||||
|
pin_mode(td, PullUp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default values
|
||||||
|
obj->CanHandle.Instance = (FDCAN_GlobalTypeDef *)can;
|
||||||
|
|
||||||
|
/* Bit time parameter
|
||||||
|
ex with 100 kHz requested frequency hz
|
||||||
|
fdcan_ker_ck | 10 MHz | 10 MHz
|
||||||
|
Prescaler | 1 | 1
|
||||||
|
Time_quantum (tq) | 100 ns | 100 ns
|
||||||
|
Bit_rate | 0.1 MBit/s | <hz>
|
||||||
|
Bit_length | 10 µs = 100 tq | <n_tq> = 10 000 000 / <hz>
|
||||||
|
Synchronization_segment | 1 tq | 1 tq
|
||||||
|
Phase_segment_1 | 69 tq | <nts1> = <n_tq> * 0.75
|
||||||
|
Phase_segment_2 | 30 tq | <nts2> = <n_tq> - 1 - <nts1>
|
||||||
|
Synchronization_Jump_width | 30 tq | <nsjw> = <nts2>
|
||||||
|
*/
|
||||||
|
int ntq = 10000000 / hz;
|
||||||
|
|
||||||
|
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.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
|
||||||
|
obj->CanHandle.Init.MessageRAMOffset = 0;
|
||||||
|
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.RxFifo0ElmtsNbr = 8;
|
||||||
|
obj->CanHandle.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
|
||||||
|
obj->CanHandle.Init.RxFifo1ElmtsNbr = 0;
|
||||||
|
obj->CanHandle.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
|
||||||
|
obj->CanHandle.Init.RxBuffersNbr = 0;
|
||||||
|
obj->CanHandle.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
|
||||||
|
obj->CanHandle.Init.TxEventsNbr = 3;
|
||||||
|
obj->CanHandle.Init.TxBuffersNbr = 0;
|
||||||
|
obj->CanHandle.Init.TxFifoQueueElmtsNbr = 3;
|
||||||
|
obj->CanHandle.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
|
||||||
|
obj->CanHandle.Init.TxElmtSize = FDCAN_DATA_BYTES_8;
|
||||||
|
|
||||||
|
can_internal_init(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void can_irq_init(can_t *obj, can_irq_handler handler, uint32_t id)
|
||||||
|
{
|
||||||
|
irq_handler = handler;
|
||||||
|
can_irq_ids[obj->index] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_irq_free(can_t *obj)
|
||||||
|
{
|
||||||
|
CANName can = (CANName)obj->CanHandle.Instance;
|
||||||
|
if (can == CAN_1) {
|
||||||
|
HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
|
||||||
|
HAL_NVIC_DisableIRQ(FDCAN1_IT1_IRQn);
|
||||||
|
}
|
||||||
|
#if defined(FDCAN2_BASE)
|
||||||
|
else if (can == CAN_2) {
|
||||||
|
HAL_NVIC_DisableIRQ(FDCAN2_IT0_IRQn);
|
||||||
|
HAL_NVIC_DisableIRQ(FDCAN2_IT1_IRQn);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HAL_NVIC_DisableIRQ(FDCAN_CAL_IRQn);
|
||||||
|
can_irq_ids[obj->index] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_free(can_t *obj)
|
||||||
|
{
|
||||||
|
__HAL_RCC_FDCAN_FORCE_RESET();
|
||||||
|
__HAL_RCC_FDCAN_RELEASE_RESET();
|
||||||
|
__HAL_RCC_FDCAN_CLK_DISABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Reset CAN interface.
|
||||||
|
*
|
||||||
|
* To use after error overflow.
|
||||||
|
*/
|
||||||
|
void can_reset(can_t *obj)
|
||||||
|
{
|
||||||
|
can_mode(obj, MODE_RESET);
|
||||||
|
HAL_FDCAN_ResetTimeoutCounter(&obj->CanHandle);
|
||||||
|
HAL_FDCAN_ResetTimestampCounter(&obj->CanHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int can_frequency(can_t *obj, int f)
|
||||||
|
{
|
||||||
|
if (HAL_FDCAN_Stop(&obj->CanHandle) != HAL_OK) {
|
||||||
|
error("HAL_FDCAN_Stop error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See can_init_freq function for calculation details */
|
||||||
|
int ntq = 10000000 / f;
|
||||||
|
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
|
||||||
|
|
||||||
|
return can_internal_init(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Filter out incoming messages
|
||||||
|
*
|
||||||
|
* @param obj CAN object
|
||||||
|
* @param id the id to filter on
|
||||||
|
* @param mask the mask applied to the id
|
||||||
|
* @param format format to filter on
|
||||||
|
* @param handle message filter handle (not supported yet)
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* 0 if filter change failed or unsupported,
|
||||||
|
* new filter handle if successful (not supported yet => returns 1)
|
||||||
|
*/
|
||||||
|
int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle)
|
||||||
|
{
|
||||||
|
UNUSED(handle); // Not supported yet (seems to be a used in read function?)
|
||||||
|
|
||||||
|
FDCAN_FilterTypeDef sFilterConfig = {0};
|
||||||
|
|
||||||
|
if (format == CANStandard) {
|
||||||
|
sFilterConfig.IdType = FDCAN_STANDARD_ID;
|
||||||
|
sFilterConfig.FilterIndex = 0;
|
||||||
|
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
|
||||||
|
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
||||||
|
sFilterConfig.FilterID1 = id;
|
||||||
|
sFilterConfig.FilterID2 = mask;
|
||||||
|
} else if (format == CANExtended) {
|
||||||
|
sFilterConfig.IdType = FDCAN_EXTENDED_ID;
|
||||||
|
sFilterConfig.FilterIndex = 0;
|
||||||
|
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
|
||||||
|
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
|
||||||
|
sFilterConfig.FilterID1 = id;
|
||||||
|
sFilterConfig.FilterID2 = mask;
|
||||||
|
} else { // Filter for CANAny format cannot be configured for STM32
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HAL_FDCAN_ConfigFilter(&obj->CanHandle, &sFilterConfig) != HAL_OK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int can_write(can_t *obj, CAN_Message msg, int cc)
|
||||||
|
{
|
||||||
|
FDCAN_TxHeaderTypeDef TxHeader = {0};
|
||||||
|
|
||||||
|
UNUSED(cc);
|
||||||
|
|
||||||
|
// Configure Tx buffer message
|
||||||
|
TxHeader.Identifier = msg.id;
|
||||||
|
if (msg.format == CANStandard) {
|
||||||
|
TxHeader.IdType = FDCAN_STANDARD_ID;
|
||||||
|
} else {
|
||||||
|
TxHeader.IdType = FDCAN_EXTENDED_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
|
||||||
|
TxHeader.DataLength = msg.len << 16;
|
||||||
|
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
|
||||||
|
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
|
||||||
|
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
|
||||||
|
TxHeader.TxEventFifoControl = FDCAN_STORE_TX_EVENTS;
|
||||||
|
TxHeader.MessageMarker = 0;
|
||||||
|
|
||||||
|
if (HAL_FDCAN_AddMessageToTxFifoQ(&obj->CanHandle, &TxHeader, msg.data) != HAL_OK) {
|
||||||
|
// Note for debug: you can get the error code calling HAL_FDCAN_GetError(&obj->CanHandle)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int can_read(can_t *obj, CAN_Message *msg, int handle)
|
||||||
|
{
|
||||||
|
UNUSED(handle); // Not supported yet (seems to be a handle to a filter configuration?)
|
||||||
|
|
||||||
|
if (HAL_FDCAN_GetRxFifoFillLevel(&obj->CanHandle, FDCAN_RX_FIFO0) == 0) {
|
||||||
|
return 0; // No message arrived
|
||||||
|
}
|
||||||
|
|
||||||
|
FDCAN_RxHeaderTypeDef RxHeader = {0};
|
||||||
|
if (HAL_FDCAN_GetRxMessage(&obj->CanHandle, FDCAN_RX_FIFO0, &RxHeader, msg->data) != HAL_OK) {
|
||||||
|
error("HAL_FDCAN_GetRxMessage error\n"); // Should not occur as previous HAL_FDCAN_GetRxFifoFillLevel call reported some data
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RxHeader.IdType == FDCAN_STANDARD_ID) {
|
||||||
|
msg->format = CANStandard;
|
||||||
|
} else {
|
||||||
|
msg->format = CANExtended;
|
||||||
|
}
|
||||||
|
msg->id = RxHeader.Identifier;
|
||||||
|
msg->type = CANData;
|
||||||
|
msg->len = RxHeader.DataLength >> 16; // see FDCAN_data_length_code value
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char can_rderror(can_t *obj)
|
||||||
|
{
|
||||||
|
FDCAN_ErrorCountersTypeDef ErrorCounters;
|
||||||
|
|
||||||
|
HAL_FDCAN_GetErrorCounters(&obj->CanHandle, &ErrorCounters);
|
||||||
|
|
||||||
|
return (unsigned char)ErrorCounters.RxErrorCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char can_tderror(can_t *obj)
|
||||||
|
{
|
||||||
|
FDCAN_ErrorCountersTypeDef ErrorCounters;
|
||||||
|
|
||||||
|
HAL_FDCAN_GetErrorCounters(&obj->CanHandle, &ErrorCounters);
|
||||||
|
|
||||||
|
return (unsigned char)ErrorCounters.TxErrorCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void can_monitor(can_t *obj, int silent)
|
||||||
|
{
|
||||||
|
CanMode mode = MODE_NORMAL;
|
||||||
|
if (silent) {
|
||||||
|
switch (obj->CanHandle.Init.Mode) {
|
||||||
|
case FDCAN_MODE_INTERNAL_LOOPBACK:
|
||||||
|
mode = MODE_TEST_SILENT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mode = MODE_SILENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (obj->CanHandle.Init.Mode) {
|
||||||
|
case FDCAN_MODE_INTERNAL_LOOPBACK:
|
||||||
|
case FDCAN_MODE_EXTERNAL_LOOPBACK:
|
||||||
|
mode = MODE_TEST_LOCAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mode = MODE_NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
can_mode(obj, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Change CAN operation to the specified mode
|
||||||
|
*
|
||||||
|
* @param mode The new operation mode (MODE_RESET, MODE_NORMAL, MODE_SILENT, MODE_TEST_LOCAL, MODE_TEST_GLOBAL, MODE_TEST_SILENT)
|
||||||
|
*
|
||||||
|
* @returns
|
||||||
|
* 0 if mode change failed or unsupported,
|
||||||
|
* 1 if mode change was successful
|
||||||
|
*/
|
||||||
|
int can_mode(can_t *obj, CanMode mode)
|
||||||
|
{
|
||||||
|
if (HAL_FDCAN_Stop(&obj->CanHandle) != HAL_OK) {
|
||||||
|
error("HAL_FDCAN_Stop error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_RESET:
|
||||||
|
break;
|
||||||
|
case MODE_NORMAL:
|
||||||
|
obj->CanHandle.Init.Mode = FDCAN_MODE_NORMAL;
|
||||||
|
// obj->CanHandle.Init.NominalPrescaler = 100; // Prescaler
|
||||||
|
break;
|
||||||
|
case MODE_SILENT: // Bus Monitoring
|
||||||
|
obj->CanHandle.Init.Mode = FDCAN_MODE_BUS_MONITORING;
|
||||||
|
break;
|
||||||
|
case MODE_TEST_GLOBAL: // External LoopBack
|
||||||
|
case MODE_TEST_LOCAL:
|
||||||
|
obj->CanHandle.Init.Mode = FDCAN_MODE_EXTERNAL_LOOPBACK;
|
||||||
|
break;
|
||||||
|
case MODE_TEST_SILENT: // Internal LoopBack
|
||||||
|
obj->CanHandle.Init.Mode = FDCAN_MODE_INTERNAL_LOOPBACK;
|
||||||
|
// obj->CanHandle.Init.NominalPrescaler = 1; // Prescaler
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return can_internal_init(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void can_irq(CANName name, int id)
|
||||||
|
{
|
||||||
|
FDCAN_HandleTypeDef CanHandle;
|
||||||
|
CanHandle.Instance = (FDCAN_GlobalTypeDef *)name;
|
||||||
|
|
||||||
|
if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_TX_COMPLETE)) {
|
||||||
|
if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_FLAG_TX_COMPLETE)) {
|
||||||
|
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_FLAG_TX_COMPLETE);
|
||||||
|
irq_handler(can_irq_ids[id], IRQ_TX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
irq_handler(can_irq_ids[id], IRQ_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_ERROR_PASSIVE)) {
|
||||||
|
if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_FLAG_ERROR_PASSIVE)) {
|
||||||
|
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_FLAG_ERROR_PASSIVE);
|
||||||
|
irq_handler(can_irq_ids[id], IRQ_PASSIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__HAL_FDCAN_GET_IT_SOURCE(&CanHandle, FDCAN_IT_BUS_OFF)) {
|
||||||
|
if (__HAL_FDCAN_GET_FLAG(&CanHandle, FDCAN_FLAG_BUS_OFF)) {
|
||||||
|
__HAL_FDCAN_CLEAR_FLAG(&CanHandle, FDCAN_FLAG_BUS_OFF);
|
||||||
|
irq_handler(can_irq_ids[id], IRQ_BUS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDCAN1_IT0_IRQHandler(void)
|
||||||
|
{
|
||||||
|
can_irq(CAN_1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDCAN1_IT1_IRQHandler(void)
|
||||||
|
{
|
||||||
|
can_irq(CAN_1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDCAN2_IT0_IRQHandler(void)
|
||||||
|
{
|
||||||
|
can_irq(CAN_2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FDCAN2_IT1_IRQHandler(void)
|
||||||
|
{
|
||||||
|
can_irq(CAN_2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add other interrupts ?
|
||||||
|
void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
|
||||||
|
{
|
||||||
|
uint32_t interrupts = 0;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case IRQ_TX:
|
||||||
|
interrupts = FDCAN_IT_TX_COMPLETE;
|
||||||
|
break;
|
||||||
|
case IRQ_RX:
|
||||||
|
interrupts = FDCAN_IT_RX_BUFFER_NEW_MESSAGE;
|
||||||
|
break;
|
||||||
|
case IRQ_ERROR:
|
||||||
|
interrupts = FDCAN_IT_ERROR_WARNING;
|
||||||
|
break;
|
||||||
|
case IRQ_PASSIVE:
|
||||||
|
interrupts = FDCAN_IT_ERROR_PASSIVE;
|
||||||
|
break;
|
||||||
|
case IRQ_BUS:
|
||||||
|
interrupts = FDCAN_IT_BUS_OFF;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
HAL_FDCAN_ActivateNotification(&obj->CanHandle, interrupts, 0);
|
||||||
|
} else {
|
||||||
|
HAL_FDCAN_DeactivateNotification(&obj->CanHandle, interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
NVIC_SetVector(FDCAN1_IT0_IRQn, (uint32_t)&FDCAN1_IT0_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
|
||||||
|
NVIC_SetVector(FDCAN1_IT1_IRQn, (uint32_t)&FDCAN1_IT1_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(FDCAN1_IT1_IRQn);
|
||||||
|
#if defined(FDCAN2_BASE)
|
||||||
|
NVIC_SetVector(FDCAN2_IT0_IRQn, (uint32_t)&FDCAN2_IT0_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(FDCAN2_IT0_IRQn);
|
||||||
|
NVIC_SetVector(FDCAN2_IT1_IRQn, (uint32_t)&FDCAN2_IT1_IRQHandler);
|
||||||
|
NVIC_EnableIRQ(FDCAN2_IT1_IRQn);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* FDCAN1 */
|
||||||
|
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "pinmap.h"
|
#include "pinmap.h"
|
||||||
#include "PeripheralPins.h"
|
#include "PeripheralPins.h"
|
||||||
|
@ -454,8 +943,6 @@ int can_mode(can_t *obj, CanMode mode)
|
||||||
|
|
||||||
int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle)
|
int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
// filter for CANAny format cannot be configured for STM32
|
// filter for CANAny format cannot be configured for STM32
|
||||||
if ((format == CANStandard) || (format == CANExtended)) {
|
if ((format == CANStandard) || (format == CANExtended)) {
|
||||||
CAN_FilterConfTypeDef sFilterConfig;
|
CAN_FilterConfTypeDef sFilterConfig;
|
||||||
|
@ -480,9 +967,9 @@ int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t
|
||||||
sFilterConfig.BankNumber = 14 + handle;
|
sFilterConfig.BankNumber = 14 + handle;
|
||||||
|
|
||||||
HAL_CAN_ConfigFilter(&obj->CanHandle, &sFilterConfig);
|
HAL_CAN_ConfigFilter(&obj->CanHandle, &sFilterConfig);
|
||||||
retval = handle;
|
|
||||||
}
|
}
|
||||||
return retval;
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void can_irq(CANName name, int id)
|
static void can_irq(CANName name, int id)
|
||||||
|
@ -716,4 +1203,6 @@ void can_irq_set(can_t *obj, CanIrqType type, uint32_t enable)
|
||||||
NVIC_EnableIRQ(irq_n);
|
NVIC_EnableIRQ(irq_n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* FDCAN1 */
|
||||||
|
|
||||||
#endif // DEVICE_CAN
|
#endif // DEVICE_CAN
|
||||||
|
|
|
@ -3001,6 +3001,7 @@
|
||||||
"detect_code": ["0813"],
|
"detect_code": ["0813"],
|
||||||
"device_has_add": [
|
"device_has_add": [
|
||||||
"ANALOGOUT",
|
"ANALOGOUT",
|
||||||
|
"CAN",
|
||||||
"CRC",
|
"CRC",
|
||||||
"TRNG",
|
"TRNG",
|
||||||
"FLASH",
|
"FLASH",
|
||||||
|
|
Loading…
Reference in New Issue