test

Fork of CANnucleo by Zoltan Hudak

can_api.c

Committer:
hudakz
Date:
2015-07-19
Revision:
1:eb04f7f0478d
Parent:
0:e29bc8e0dddd
Child:
2:09a0d2838572

File content as of revision 1:eb04f7f0478d:

/*
 can_api.c for STMicroelectronics mbed boards equipped with Controller Area Network interface:

 NUCLEO-F072RB
 NUCLEO-F091RC
 NUCLEO-F103RB
 NUCLEO-F302R8
 NUCLEO-F303RE
 NUCLEO-F334R8
 DISCO-F334C8

 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) {
    HAL_NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);

#if defined(TARGET_NUCLEO_F103RB) || \
    defined(TARGET_NUCLEO_F302R8) || \
    defined(TARGET_NUCLEO_F303RE) || \
    defined(TARGET_NUCLEO_F334R8) || \
    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_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(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
}