test

Fork of CANnucleo by Zoltan Hudak

can_api.c

Committer:
hudakz
Date:
2015-08-04
Revision:
5:b53e5ee15315
Parent:
3:0fae6b54a2ee
Child:
6:c5a40d5fd9f1

File content as of revision 5:b53e5ee15315:

/*
  ******************************************************************************
  * @file    can_api.c
  * @author  Zoltan Hudak
  * @version 
  * @date    04-August-2015
  * @brief   CAN api for NUCLEO-F103RB platform
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; 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);

    // 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;
    }

    HAL_CAN_Init(&_canHandle);
    HAL_NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
    
    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 = 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) {
#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) {
    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(int 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;
    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);
    
    return 1;
}

/**
 * @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
}