pub
Fork of CANnucleo by
can_api.c
- Committer:
- hudakz
- Date:
- 2015-12-30
- Revision:
- 17:1fd35431ee8e
- Parent:
- 16:f4c8f45bded9
- Child:
- 20:bcd8161f8f6c
File content as of revision 17:1fd35431ee8e:
/* ****************************************************************************** * @file can_api.c * @author Zoltan Hudak * @version * @date 04-August-2015 * @brief CAN api for NUCLEO-F103RB platform ****************************************************************************** * @attention * * <h2><center>© 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 "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, FunctionalState abom) { initCAN(obj, rd, td, abom); can_filter(obj, 0, 0, CANAny, 0); } /** * @brief * @note * @param * @retval */ void can_free(can_t* obj) { HAL_CAN_MspDeInit(&_canHandle); } /** * @brief * @note * @param * @retval */ int can_frequency(can_t* obj, int hz) { HAL_NVIC_DisableIRQ(CAN_IRQ); #if defined(TARGET_NUCLEO_F072RB) || \ defined(TARGET_NUCLEO_F091RC) // APB1 peripheral 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) _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; } #elif defined(TARGET_NUCLEO_F103RB) || \ defined(TARGET_NUCLEO_F303RE) || \ defined(TARGET_NUCLEO_F303K8) || \ defined(TARGET_NUCLEO_F334R8) || \ defined(TARGET_DISCO_F334C8) // APB1 peripheral 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) #if DEBUG printf("Unknown frequency specified!\r\n"); printf("Using default 125kbps\r\n"); #endif _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_F446RE) // APB1 peripheral clock = 45000000Hz switch(hz) { case 1000000: // 1000kbps bit rate _canHandle.Init.Prescaler = 5; // number of time quanta = 45000000/5/1000000 = 9 _canHandle.Init.SJW = CAN_SJW_1TQ; _canHandle.Init.BS1 = CAN_BS1_6TQ; // sample point at: (1 + 6) / 9 * 100 = 77.78% _canHandle.Init.BS2 = CAN_BS2_2TQ; break; case 500000: // 500kbps bit rate _canHandle.Init.Prescaler = 10; // number of time quanta = 45000000/10/500000 = 9 _canHandle.Init.SJW = CAN_SJW_1TQ; _canHandle.Init.BS1 = CAN_BS1_6TQ; // sample point at: (1 + 6) / 9 * 100 = 77.78% _canHandle.Init.BS2 = CAN_BS2_2TQ; break; case 250000: // 250kbps _canHandle.Init.Prescaler = 15; // number of time quanta = 45000000/15/250000 = 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 125000: // 125kbps _canHandle.Init.Prescaler = 30; // number of time quanta = 45000000/30/125000 = 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; default: // 125kbps (default) #if DEBUG printf("Unknown frequency specified!\r\n"); printf("Using default 125kbps\r\n"); #endif _canHandle.Init.Prescaler = 30; // number of time quanta = 45000000/30/125000 = 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; } #endif HAL_CAN_Init(&_canHandle); HAL_NVIC_EnableIRQ(CAN_IRQ); return 1; } /** * @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) { #ifdef DEBUG printf("CAN reception initialization error\r\n"); #endif } } /** * @brief * @note * @param * @retval */ void can_irq_free(can_t* obj) { rxCompleteCallback = 0; } /** * @brief * @note * @param * @retval */ 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) { #ifdef DEBUG printf("Transmission error\r\n"); #endif return 0; } else return 1; } /** * @brief * @note * @param * @retval */ int can_read(can_t* obj, CAN_Message* msg, int handle) { int i; 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]; return msg->len; } /** * @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; } 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; // Specifies the filter number (must be a number between 0 and 13 at 32-bit filter scale) 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 = 0; // Selects the start bank filter return 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 }