pub
Fork of CANnucleo by
Diff: can_api.c
- Revision:
- 0:e29bc8e0dddd
- Child:
- 1:eb04f7f0478d
diff -r 000000000000 -r e29bc8e0dddd can_api.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/can_api.c Sun Jul 19 09:06:26 2015 +0000 @@ -0,0 +1,353 @@ +/* + can_api.c for STMicroelectronics mbed boards equipped with Controller Area Network interface: + + NUCLEO-F070RB + NUCLEO-F072RB + NUCLEO-F103RB + NUCLEO-F302R8 + NUCLEO-F334R8 + NUCLEO-F303RE + NUCLEO-F091RC + DISCO-F334C8 + DISCO-F746NG + + Copyright (c) 2015 Zoltan Hudak <hudakz@inbox.com> + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "stm32f1xx_hal.h" +#include "can_api.h" +#include "can_helper.h" +#include "pinmap.h" + +extern void (*rxCompleteCallback) (void); +extern CAN_HandleTypeDef _canHandle; + +/** + * @brief + * @note + * @param + * @retval + */ +void can_init(can_t* obj, PinName rd, PinName td) { + initCAN(obj, rd, td); + can_filter(obj, 0, 0, CANAny, 0); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void can_free(can_t* obj) { + HAL_CAN_MspDeInit(obj); +} + +/** + * @brief + * @note + * @param + * @retval + */ +int can_frequency(can_t* obj, int hz) { + + /* Disable the NVIC for CAN reception */ + + HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); + +#if defined(TARGET_NUCLEO_F103RB) || \ + defined(TARGET_NUCLEO_F302R8) || \ + defined(TARGET_NUCLEO_F334R8) || \ + defined(TARGET_NUCLEO_F303RE) || \ + defined(TARGET_DISCO_F334C8) + // APB1 pheripheral clock = 36000000Hz + + switch(hz) { + case 1000000: + // 1000kbps bit rate + _canHandle.Init.Prescaler = 3; // number of time quanta = 36000000/3/1000000 = 12 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_3TQ; + break; + + case 500000: + // 500kbps bit rate + _canHandle.Init.Prescaler = 6; // number of time quanta = 36000000/6/500000 = 12 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_3TQ; + break; + + case 250000: + // 250kbps + _canHandle.Init.Prescaler = 9; // number of time quanta = 36000000/9/250000 = 16 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_4TQ; + break; + + case 125000: + // 125kbps + _canHandle.Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_4TQ; + break; + + default: + // 125kbps (default) + printf("Unknown frequency specified!\r\n"); + printf("Using default 125kbps\r\n"); + _canHandle.Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_4TQ; + } + +#elif defined(TARGET_NUCLEO_F070RB) || \ + defined(TARGET_NUCLEO_F072RB) || \ + defined(TARGET_NUCLEO_F091RC) + // APB1 pheripheral clock = 48000000Hz + + switch(hz) { + case 1000000: + // 1000kbps bit rate + _canHandle.Init.Prescaler = 4; // number of time quanta = 48000000/4/1000000 = 12 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_3TQ; + break; + + case 500000: + // 500kbps bit rate + _canHandle.Init.Prescaler = 8; // number of time quanta = 48000000/8/500000 = 12 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_3TQ; + break; + + case 250000: + // 250kbps + _canHandle.Init.Prescaler = 12; // number of time quanta = 48000000/12/250000 = 16 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_4TQ; + break; + + case 125000: + // 125kbps + _canHandle.Init.Prescaler = 24; // number of time quanta = 48000000/24/125000 = 16 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_4TQ; + break; + + default: + // 125kbps (default) + printf("Unknown frequency specified!\r\n"); + printf("Using default 125kbps\r\n"); + _canHandle.Init.Prescaler = 24; // number of time quanta = 48000000/24/125000 = 16 + _canHandle.Init.SJW = CAN_SJW_1TQ; + _canHandle.Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + _canHandle.Init.BS2 = CAN_BS2_4TQ; + } +#endif + HAL_CAN_Init(&_canHandle); + HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void can_irq_init(can_t* obj, can_irq_handler handler, uint32_t id) { + if(HAL_CAN_Receive_IT(&_canHandle, CAN_FIFO0) != HAL_OK) { + printf("CAN reception initialization error\r\n"); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void can_irq_free(can_t* obj) { + rxCompleteCallback = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +//void can_irq_set(can_t* obj, CanIrqType irq, uint32_t enable) +//{ + +//} +void can_irq_set(void (*fptr) (void)) { + rxCompleteCallback = fptr; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int can_write(can_t* obj, CAN_Message msg, int cc) { + int i = 0; + + if(msg.format == CANStandard) { + _canHandle.pTxMsg->StdId = msg.id; + _canHandle.pTxMsg->ExtId = 0x00; + } + else { + _canHandle.pTxMsg->StdId = 0x00; + _canHandle.pTxMsg->ExtId = msg.id; + } + + _canHandle.pTxMsg->RTR = msg.type == CANData ? CAN_RTR_DATA : CAN_RTR_REMOTE; + _canHandle.pTxMsg->IDE = msg.format == CANStandard ? CAN_ID_STD : CAN_ID_EXT; + _canHandle.pTxMsg->DLC = msg.len; + + for(i = 0; i < msg.len; i++) + _canHandle.pTxMsg->Data[i] = msg.data[i]; + + if(HAL_CAN_Transmit(&_canHandle, 10) != HAL_OK) { + printf("Transmission error\r\n"); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +int can_read(can_t* obj, CAN_Message* msg, int handle) { + int i = 0; + + msg->id = _canHandle.pRxMsg->IDE == CAN_ID_STD ? _canHandle.pRxMsg->StdId : _canHandle.pRxMsg->ExtId; + msg->type = _canHandle.pRxMsg->RTR == CAN_RTR_DATA ? CANData : CANRemote; + msg->format = _canHandle.pRxMsg->IDE == CAN_ID_STD ? CANStandard : CANExtended; + msg->len = _canHandle.pRxMsg->DLC; + for(i = 0; i < msg->len; i++) + msg->data[i] = _canHandle.pRxMsg->Data[i]; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int can_mode(can_t* obj, CanMode mode) { + switch(mode) { + case MODE_RESET: + return HAL_ERROR; + + case MODE_NORMAL: + _canHandle.Init.Mode = CAN_MODE_NORMAL; + break; + + case MODE_SILENT: + _canHandle.Init.Mode = CAN_MODE_SILENT; + break; + + case MODE_TEST_GLOBAL: + _canHandle.Init.Mode = CAN_MODE_LOOPBACK; + break; + + case MODE_TEST_LOCAL: + _canHandle.Init.Mode = CAN_MODE_LOOPBACK; + break; + + case MODE_TEST_SILENT: + _canHandle.Init.Mode = CAN_MODE_SILENT_LOOPBACK; + break; + } + + _canHandle.Init.Mode = CAN_MODE_NORMAL; + return HAL_CAN_Init(&_canHandle); +} + +/** + * @brief + * @note + * @param + * @retval + */ +int can_filter(can_t* obj, uint32_t id, uint32_t mask, CANFormat format /*=CANAny*/, int32_t handle /*=0*/ ) { + CAN_FilterConfTypeDef sFilterConfig; + + sFilterConfig.FilterNumber = handle; + sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; + sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; + sFilterConfig.FilterIdHigh = (((id) >> 16) & 0xFFFF); + sFilterConfig.FilterIdLow = ((id) & 0xFFFF); + sFilterConfig.FilterMaskIdHigh = (((mask) >> 16) & 0xFFFF); + sFilterConfig.FilterMaskIdLow = ((mask) & 0xFFFF); + sFilterConfig.FilterFIFOAssignment = 0; + sFilterConfig.FilterActivation = ENABLE; + sFilterConfig.BankNumber = 14; + HAL_CAN_ConfigFilter(&_canHandle, &sFilterConfig); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void can_reset(can_t* obj) { + __HAL_CAN_RESET_HANDLE_STATE(&_canHandle); +} + +/** + * @brief + * @note + * @param + * @retval + */ +unsigned char can_rderror(can_t* obj) { + return HAL_CAN_GetError(&_canHandle); +} + +/** + * @brief + * @note + * @param + * @retval + */ +unsigned char can_tderror(can_t* obj) { + return HAL_CAN_GetError(&_canHandle); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void can_monitor(can_t* obj, int silent) { + + // not implemented +}