mbed library sources, include can_api for nucleo-f091rc
Dependents: CanNucleoF0_example
Fork of mbed-src by
Revision 639:15f853e90e6b, committed 2015-12-16
- Comitter:
- ptpaterson
- Date:
- Wed Dec 16 05:53:00 2015 +0000
- Parent:
- 638:ceaaef393d2e
- Child:
- 640:7eb9b8c299cd
- Commit message:
- Using read without interrupts. Implemented message_queue, but not quite working.
Changed in this revision
--- a/targets/hal/TARGET_STM/TARGET_STM32F0/TARGET_NUCLEO_F091RC/objects.h Mon Dec 14 16:23:14 2015 +0000 +++ b/targets/hal/TARGET_STM/TARGET_STM32F0/TARGET_NUCLEO_F091RC/objects.h Wed Dec 16 05:53:00 2015 +0000 @@ -101,7 +101,8 @@ }; struct can_s { - CAN_HandleTypeDef *hcan; + CAN_HandleTypeDef *hcan; + int index; }; #include "gpio_object.h"
--- a/targets/hal/TARGET_STM/TARGET_STM32F0/can_api.c Mon Dec 14 16:23:14 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,632 +0,0 @@ -/* - ****************************************************************************** - * @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 <[email protected]> - * - * 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/>. - */ - - /* Some code reused from STM32CubeMX */ - /****************************************************************************** - * - * COPYRIGHT(c) 2015 STMicroelectronics - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - - /* also some code taken from other mbed can_api.c */ - - /* mbed Microcontroller Library - * Copyright (c) 2006-2013 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. - */ - - /* Modified by Paul Paterson */ - -#include "stm32f0xx_hal.h" -#include "can_api.h" -#include "can_helper.h" -#include "pinmap.h" - -static PinName pinRd; -static PinName pinTd; - -/** - * @brief - * @note - * @param - * @retval - */ -void -can_init (can_t *obj, - PinName rd, - PinName td) -{ - /* file scope so that they can be referenced in the MSP functions */ - pinRd = rd; - pinTd = td; - - /* initialize the static data */ - static CAN_HandleTypeDef hcan; - obj->hcan = &hcan; - obj->hcan->Instance = ((CAN_TypeDef *) CAN_BASE); - - static CanTxMsgTypeDef txMessage; - static CanRxMsgTypeDef rxMessage; - obj->hcan->pTxMsg = &txMessage; - obj->hcan->pRxMsg = &rxMessage; - - /* set operation mode */ - obj->hcan->Init.TTCM = DISABLE; - obj->hcan->Init.ABOM = DISABLE; - obj->hcan->Init.AWUM = DISABLE; - obj->hcan->Init.NART = DISABLE; - obj->hcan->Init.RFLM = DISABLE; - obj->hcan->Init.TXFP = DISABLE; - obj->hcan->Init.Mode = CAN_MODE_NORMAL; - - /* set th default frequency - * 125kbps bit rate (default) - * APB1 peripheral clock = 36000000Hz - */ - obj->hcan->Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 - obj->hcan->Init.SJW = CAN_SJW_1TQ; - obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at (1 + 11) / 16 * 100 = 75% - obj->hcan->Init.BS2 = CAN_BS2_4TQ; - - int result = HAL_CAN_Init (obj->hcan); - if (result != HAL_OK) - { - // TODO: handle issues - } - - /* minimum filter required to make this work */ - can_filter (obj, 0, 0, CANAny, 0); - - return; -} - -/** - * @brief - * @note - * @param - * @retval - */ -void -can_free (can_t *obj) -{ - HAL_CAN_DeInit (obj->hcan); -} - -/** - * @brief - * @note - * @param - * @retval - */ -int -can_frequency(can_t *obj, - int hz) -{ - HAL_NVIC_DisableIRQ(CEC_CAN_IRQn); - - // APB1 peripheral clock = 36000000Hz - - switch(hz) { - case 1000000: - // 1000kbps bit rate - obj->hcan->Init.Prescaler = 3; // number of time quanta = 36000000/3/1000000 = 12 - obj->hcan->Init.SJW = CAN_SJW_1TQ; - obj->hcan->Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% - obj->hcan->Init.BS2 = CAN_BS2_3TQ; - break; - - case 500000: - // 500kbps bit rate - obj->hcan->Init.Prescaler = 6; // number of time quanta = 36000000/6/500000 = 12 - obj->hcan->Init.SJW = CAN_SJW_1TQ; - obj->hcan->Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% - obj->hcan->Init.BS2 = CAN_BS2_3TQ; - break; - - case 250000: - // 250kbps - obj->hcan->Init.Prescaler = 9; // number of time quanta = 36000000/9/250000 = 16 - obj->hcan->Init.SJW = CAN_SJW_1TQ; - obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% - obj->hcan->Init.BS2 = CAN_BS2_4TQ; - break; - - case 125000: - // 125kbps - obj->hcan->Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 - obj->hcan->Init.SJW = CAN_SJW_1TQ; - obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% - obj->hcan->Init.BS2 = CAN_BS2_4TQ; - break; - - default: - // 125kbps (default) - obj->hcan->Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 - obj->hcan->Init.SJW = CAN_SJW_1TQ; - obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% - obj->hcan->Init.BS2 = CAN_BS2_4TQ; - } - HAL_CAN_Init(obj->hcan); - - /* HAL_CAN_INIT will call HAL_CAN_MspInit, which will init the interupts */ - - return 1; -} - -/* - * these will get setup in can_irq_init() - * and used later in HAL_CAN_RxCpltCallback() - */ - -/* becomes a pointer to the member function Can::_irq_handler */ -static can_irq_handler irq_handler; - -/* id is really just a pointer to the Can object - * useful for uC's that have multiple CAN devices - */ -static uint32_t can_irq_id; - -/** - * @brief - * @note - * @param - * @retval - */ -void -can_irq_init (can_t *obj, - can_irq_handler handler, - uint32_t id) -{ - - printf ("function: can_irq_init()\r\n"); - - irq_handler = handler; - can_irq_id = id; - - if (HAL_CAN_Receive_IT (obj->hcan, CAN_FIFO0) != HAL_OK) - { - // TODO: handle issues - } -} - -/** - * @brief - * @note - * @param - * @retval - */ -void -can_irq_free (can_t *obj) -{ - // TODO: free any resources not called by HAL_CAN_DeInit() */ -} - -/** - * @brief - * @note - * @param - * @retval - */ -void -can_irq_set (can_t *obj, - CanIrqType irq, - uint32_t enable) -{ - -} - -/** - * @brief - * @note - * @param - * @retval - */ -int -can_write (can_t *obj, - CAN_Message msg, - int cc) -{ - if (msg.format == CANStandard) - { - obj->hcan->pTxMsg->StdId = msg.id; - obj->hcan->pTxMsg->ExtId = 0x00; - } - else - { - obj->hcan->pTxMsg->StdId = 0x00; - obj->hcan->pTxMsg->ExtId = msg.id; - } - - obj->hcan->pTxMsg->RTR = msg.type == CANData ? CAN_RTR_DATA : CAN_RTR_REMOTE; - obj->hcan->pTxMsg->IDE = msg.format == CANStandard ? CAN_ID_STD : CAN_ID_EXT; - obj->hcan->pTxMsg->DLC = msg.len; - - // TODO: use memcopy - for (int i = 0; i < msg.len; i++) - { - obj->hcan->pTxMsg->Data[i] = msg.data[i]; - } - - int result = 1; - if (HAL_CAN_Transmit(obj->hcan, 10) != HAL_OK) - { - result = 0; - } - - return result; - -} - -/** - * @brief - * @note - * @param - * @retval - */ -int -can_read (can_t *obj, - CAN_Message *msg, - int handle) -{ - msg->id = obj->hcan->pRxMsg->IDE == CAN_ID_STD ? obj->hcan->pRxMsg->StdId : obj->hcan->pRxMsg->ExtId; - msg->type = obj->hcan->pRxMsg->RTR == CAN_RTR_DATA ? CANData : CANRemote; - msg->format = obj->hcan->pRxMsg->IDE == CAN_ID_STD ? CANStandard : CANExtended; - msg->len = obj->hcan->pRxMsg->DLC; - - // TODO: use memcopy - for (int i = 0; i < msg->len; i++) - { - msg->data[i] = obj->hcan->pRxMsg->Data[i]; - } - - return msg->len; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int -can_mode (can_t *obj, - CanMode mode) -{ - int success = 0; - - switch(mode) - { - case MODE_RESET: - success = HAL_ERROR; - break; - - case MODE_NORMAL: - obj->hcan->Init.Mode = CAN_MODE_NORMAL; - break; - - case MODE_SILENT: - obj->hcan->Init.Mode = CAN_MODE_SILENT; - break; - - case MODE_TEST_GLOBAL: - obj->hcan->Init.Mode = CAN_MODE_LOOPBACK; - break; - - case MODE_TEST_LOCAL: - obj->hcan->Init.Mode = CAN_MODE_LOOPBACK; - break; - - case MODE_TEST_SILENT: - obj->hcan->Init.Mode = CAN_MODE_SILENT_LOOPBACK; - break; - } - - if (success != HAL_ERROR) - { - success = HAL_CAN_Init(obj->hcan); - } - - return success; -} - -/** - * @brief - * @note - * @param - * @retval - */ -int -can_filter (can_t *obj, - uint32_t id, - uint32_t mask, - CANFormat format, - int32_t handle) -{ - 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(obj->hcan, &sFilterConfig); -} - -/** - * @brief - * @note - * @param - * @retval - */ -void -can_reset (can_t *obj) -{ - __HAL_CAN_RESET_HANDLE_STATE(obj->hcan); -} - -/** - * @brief - * @note - * @param - * @retval - */ -unsigned char -can_rderror (can_t *obj) -{ - return HAL_CAN_GetError(obj->hcan); -} - -/** - * @brief - * @note - * @param - * @retval - */ -unsigned char -can_tderror (can_t *obj) -{ - return HAL_CAN_GetError(obj->hcan); -} - -/** - * @brief - * @note - * @param - * @retval - */ - void - can_monitor (can_t *obj, - int silent) -{ - // TODO: implement -} - -/*============================================================================= - * HAL_MSP - *============================================================================= - */ - -/** - * @brief CAN MSP Initialization - * @param hcan: CAN handle pointer - * @retval None - */ -void -HAL_CAN_MspInit(CAN_HandleTypeDef* hcan) -{ - /* derived from STM32CubeMX */ - - GPIO_InitTypeDef GPIO_InitStruct; - if (hcan->Instance == CAN) - { - if ((pinRd == PA_11) && (pinTd == PA_12)) - { - /* Peripheral clock enable */ - __CAN_CLK_ENABLE(); - - /* Enable GPIO clock */ - __GPIOA_CLK_ENABLE(); - - /**CAN GPIO Configuration - PA11 ------> CAN_RX - PA12 ------> CAN_TX - */ - GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF4_CAN; - HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - } - else if ((pinRd == PB_8) && (pinTd == PB_9)) - { - /* Peripheral clock enable */ - __CAN_CLK_ENABLE(); - - /* Enable GPIO clock */ - __GPIOB_CLK_ENABLE(); - - /**CAN GPIO Configuration - PB8 ------> CAN_RX - PB9 ------> CAN_TX - */ - GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF4_CAN; - HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - } - else {} - } - - /* Peripheral interrupt init*/ - HAL_NVIC_SetPriority(CEC_CAN_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(CEC_CAN_IRQn); -} - -/** - * @brief CAN MSP De-Initialization - * This function frees the hardware resources used: - * - Disable the Peripheral's clock - * - Revert GPIO to their default state - * @param hcan: CAN handle pointer - * @retval None - */ -void -HAL_CAN_MspDeInit (CAN_HandleTypeDef* hcan) -{ - /* derived from STM32CubeMX */ - - if (hcan->Instance == CAN) - { - /* Peripheral clock disable */ - __CAN_CLK_DISABLE(); - - /* Disable pins*/ - if ((pinRd == PA_11) && (pinTd == PA_12)) - { - /**CAN GPIO Configuration - PA11 ------> CAN_RX - PA12 ------> CAN_TX - */ - HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12); - } - else if ((pinRd == PB_8) && (pinTd == PB_9)) - { - /**CAN GPIO Configuration - PB8 ------> CAN_RX - PB9 ------> CAN_TX - */ - HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9); - } - else {} - } - - /* Disable the NVIC for CAN reception */ - HAL_NVIC_DisableIRQ(CEC_CAN_IRQn); -} - -/** - * @brief Reception complete callback in non blocking mode - * @param obj->hcan: pointer to a CAN_HandleTypeDef structure that contains - * the configuration information for the specified CAN. - * @retval None - */ -void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan) { - // if(HAL_CAN_Receive_IT(hcan, CAN_FIFO0) == HAL_OK) { - // if(rxCompleteCallback != NULL) - // // call user callbacks - // } - // else { - // error_handler(error); - // } - - // BUG: CAN race condition if HAL_CAN_Receive_IT() is used. - // See https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Java/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Java%2FBUG%20CAN%20race%20condition%20if%20HAL%5FCAN%5FReceive%5FIT%20is%20used - // - // Fixed by Mark Burton: - // ideally, we should be able to call HAL_CAN_Receive_IT() here to set up for another - // receive but the API is flawed because that function will fail if HAL_CAN_Transmit() - // had already locked the handle when the receive interrupt occurred - so we do what - // HAL_CAN_Receive_IT() would do - - /* Call user callbacks */ - irq_handler (can_irq_id, IRQ_RX); - - /* perform HAL_CAN_Receive_IT() fix */ - if (hcan->State == HAL_CAN_STATE_BUSY_TX) - { - hcan->State = HAL_CAN_STATE_BUSY_TX_RX; - } - else - { - hcan->State = HAL_CAN_STATE_BUSY_RX; - - /* Set CAN error code to none */ - hcan->ErrorCode = HAL_CAN_ERROR_NONE; - - /* Enable Error warning Interrupt */ - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EWG); - - /* Enable Error passive Interrupt */ - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EPV); - - /* Enable Bus-off Interrupt */ - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_BOF); - - /* Enable Last error code Interrupt */ - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_LEC); - - /* Enable Error Interrupt */ - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_ERR); - } - - // Enable FIFO 0 message pending Interrupt - __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0); -} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_STM/TARGET_STM32F0/can_api.cpp Wed Dec 16 05:53:00 2015 +0000 @@ -0,0 +1,781 @@ +/* + ****************************************************************************** + * @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 <[email protected]> + * + * 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/>. + */ + +/* Some code reused from STM32CubeMX */ +/****************************************************************************** + * + * COPYRIGHT(c) 2015 STMicroelectronics + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/* also some code taken from other mbed can_api.c */ + +/* mbed Microcontroller Library +* Copyright (c) 2006-2013 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. +*/ + +/* Modified by Paul Paterson */ + +#include "stm32f0xx_hal.h" +#include "can_api.h" +#include "can_helper.h" +#include "pinmap.h" + +#include "mbed.h" + +static PinName pinRd; +static PinName pinTd; + +/** + * @brief Holder for obj* when not passed to function + * @note need this to cheat for now while we don't have a way to implement + * multiple CAN controllers + */ +static can_t *single_can_controller; + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_init (can_t *obj, + PinName rd, + PinName td) +{ + // DEBUG + printf("api: can_init\r\n"); + + /* file scope so that they can be referenced in the MSP functions */ + pinRd = rd; + pinTd = td; + + /* only one CAN controller for STM32F0, otherwise need to figure it out here */ + single_can_controller = obj; /* this is so we can cheat and call globally*/ + obj->index = 0; + + /* initialize the static data */ + static CAN_HandleTypeDef hcan; + obj->hcan = &hcan; + obj->hcan->Instance = ((CAN_TypeDef *) CAN_BASE); + + static CanTxMsgTypeDef txMessage; + static CanRxMsgTypeDef rxMessage; + obj->hcan->pTxMsg = &txMessage; + obj->hcan->pRxMsg = &rxMessage; + + /* set operation mode */ + obj->hcan->Init.TTCM = DISABLE; + obj->hcan->Init.ABOM = ENABLE; + obj->hcan->Init.AWUM = DISABLE; + obj->hcan->Init.NART = DISABLE; + obj->hcan->Init.RFLM = DISABLE; + obj->hcan->Init.TXFP = DISABLE; + obj->hcan->Init.Mode = CAN_MODE_NORMAL; + + /* set th default frequency + * 125kbps bit rate (default) + * APB1 peripheral clock = 36000000Hz + */ + obj->hcan->Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 + obj->hcan->Init.SJW = CAN_SJW_1TQ; + obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at (1 + 11) / 16 * 100 = 75% + obj->hcan->Init.BS2 = CAN_BS2_4TQ; + + int status = HAL_CAN_Init (obj->hcan); + if (status != HAL_OK) { + printf("api: can_init: HAL_CAN_INIT issue\r\n"); + } + + /* minimum filter required to make this work */ + can_filter (obj, 0, 0, CANAny, 0); + + return; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_free (can_t *obj) +{ + HAL_CAN_DeInit (obj->hcan); +} + +/** + * @brief + * @note + * @param + * @retval + */ +int +can_frequency(can_t *obj, + int hz) +{ + HAL_NVIC_DisableIRQ(CEC_CAN_IRQn); + + // APB1 peripheral clock = 36000000Hz + + switch(hz) { + case 1000000: + // 1000kbps bit rate + obj->hcan->Init.Prescaler = 3; // number of time quanta = 36000000/3/1000000 = 12 + obj->hcan->Init.SJW = CAN_SJW_1TQ; + obj->hcan->Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% + obj->hcan->Init.BS2 = CAN_BS2_3TQ; + break; + + case 500000: + // 500kbps bit rate + obj->hcan->Init.Prescaler = 6; // number of time quanta = 36000000/6/500000 = 12 + obj->hcan->Init.SJW = CAN_SJW_1TQ; + obj->hcan->Init.BS1 = CAN_BS1_8TQ; // sample point at: (1 + 8) / 12 * 100 = 75% + obj->hcan->Init.BS2 = CAN_BS2_3TQ; + break; + + case 250000: + // 250kbps + obj->hcan->Init.Prescaler = 9; // number of time quanta = 36000000/9/250000 = 16 + obj->hcan->Init.SJW = CAN_SJW_1TQ; + obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + obj->hcan->Init.BS2 = CAN_BS2_4TQ; + break; + + case 125000: + // 125kbps + obj->hcan->Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 + obj->hcan->Init.SJW = CAN_SJW_1TQ; + obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + obj->hcan->Init.BS2 = CAN_BS2_4TQ; + break; + + default: + // 125kbps (default) + obj->hcan->Init.Prescaler = 18; // number of time quanta = 36000000/18/125000 = 16 + obj->hcan->Init.SJW = CAN_SJW_1TQ; + obj->hcan->Init.BS1 = CAN_BS1_11TQ; // sample point at: (1 + 11) / 16 * 100 = 75% + obj->hcan->Init.BS2 = CAN_BS2_4TQ; + } + HAL_CAN_Init(obj->hcan); + + /* HAL_CAN_INIT will call HAL_CAN_MspInit, which will init the interupts */ + + return 1; +} + +/* + * these will get setup in can_irq_init() + * and used later in HAL_CAN_RxCpltCallback() + */ + +#define CAN_NUM 1 +#define CAN_MESSAGE_QUEUE_SIZE 10 + +/** + * @brief Queue to hold several incomming messages while we wait for the user + * to call for them. + * @note This is only necessary now, because the STM32 HAL handles the can + * receive FIFO by writing to the CAN_HandleTypeDef and popping from the built + * in queue. + */ +typedef struct { + int next; + unsigned int contain_mask; + CanRxMsgTypeDef queue[CAN_MESSAGE_QUEUE_SIZE]; +} can_message_queue; + +static can_message_queue message_queues[CAN_NUM]; + +/** becomes a pointer to the member function Can::_irq_handler */ +static can_irq_handler irq_handler; + +/** id is really just a pointer to the Can object + * useful for uC's that have multiple CAN devices + */ +static uint32_t can_irq_ids[CAN_NUM] = {0}; + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_irq_init (can_t *obj, + can_irq_handler handler, + uint32_t id) +{ + + // DEBUG + printf("api: can_irq_init\r\n"); + + irq_handler = handler; + can_irq_ids[obj->index] = id; + + message_queues[obj->index].contain_mask = 0; + message_queues[obj->index].next = CAN_MESSAGE_QUEUE_SIZE - 1; + + //if (HAL_CAN_Receive_IT (obj->hcan, CAN_FIFO0) != HAL_OK) { + // printf("api: can_irq_init: receive failed\r\n"); + //} +} + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_irq_free (can_t *obj) +{ + // TODO: free any resources not called by HAL_CAN_DeInit() */ +} + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_irq_set (can_t *obj, + CanIrqType irq, + uint32_t enable) +{ + +} + +/** + * @brief + * @note + * @param + * @retval + */ +int +can_write (can_t *obj, + CAN_Message msg, + int cc) +{ + // DEBUG + printf("api: can_write\r\n"); + + if (msg.format == CANStandard) { + obj->hcan->pTxMsg->StdId = msg.id; + obj->hcan->pTxMsg->ExtId = 0x00; + } else { + obj->hcan->pTxMsg->StdId = 0x00; + obj->hcan->pTxMsg->ExtId = msg.id; + } + + obj->hcan->pTxMsg->RTR = msg.type == CANData ? CAN_RTR_DATA : CAN_RTR_REMOTE; + obj->hcan->pTxMsg->IDE = msg.format == CANStandard ? CAN_ID_STD : CAN_ID_EXT; + obj->hcan->pTxMsg->DLC = msg.len; + + // TODO: use memcopy + for (int i = 0; i < msg.len; i++) { + obj->hcan->pTxMsg->Data[i] = msg.data[i]; + } + + int result = 1; + if (HAL_CAN_Transmit(obj->hcan, 10) != HAL_OK) { + result = 0; + } + + return result; + +} + +/** + * @brief Adds one message to the queue + * @note sends indication of overflow if it happens but overwites anyway + */ +static int message_enqueue(can_t *obj, + CanRxMsgTypeDef *msg) +{ + int result = 1; + + int next = message_queues[obj->index].next; + if (++next >= CAN_MESSAGE_QUEUE_SIZE) + next = 0; + + if (message_queues[obj->index].contain_mask & (1 << next)) + result = 0; /* overflow */ + + message_queues[obj->index].queue[next] = *msg; + message_queues[obj->index].next = next; + message_queues[obj->index].contain_mask |= next; + + return result; +} + +/** + * @brief Pops one message from the queue + * @note sends indication of overflow if it happens but overwites anyway + */ +static int message_dequeue(can_t *obj, + CanRxMsgTypeDef *msg) +{ + int result = 1; + + int next = message_queues[obj->index].next; + + if (message_queues[obj->index].contain_mask & (1 << next)) { + + *msg = message_queues[obj->index].queue[next]; + message_queues[obj->index].contain_mask &= ~next; + + if (--next < 0) + next = CAN_MESSAGE_QUEUE_SIZE - 1; + message_queues[obj->index].next = next; + + } else { + result = 0; /* no current message */ + } + + return result; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int +can_read (can_t *obj, + CAN_Message *msg, + int handle) +{ + int result = 1; + + /* having trouble with the interrupts */ + HAL_StatusTypeDef status = HAL_CAN_Receive(obj->hcan, CAN_FIFO0, 10); + if (status == HAL_OK) { + printf("api: can_read: HAL_CAN_Receive HAL_OK\r\n"); + } else if (status == HAL_TIMEOUT) { + //printf("api: can_read: HAL_CAN_Receive HAL_TIMEOUT\r\n"); + result = 0; + } else if (status == HAL_ERROR) { + printf("api: can_read: HAL_CAN_Receive HAL_ERROR\r\n"); + result = 0; + } else { + printf("api: can_read: HAL_CAN_Receive HAL_(SOMETHING ELSE)\r\n"); + result = 0; + } + + if (result > 0) { + + CanRxMsgTypeDef * popMessage = obj->hcan->pRxMsg; + + msg->id = popMessage->IDE == CAN_ID_STD ? popMessage->StdId : popMessage->ExtId; + msg->type = popMessage->RTR == CAN_RTR_DATA ? CANData : CANRemote; + msg->format = popMessage->IDE == CAN_ID_STD ? CANStandard : CANExtended; + msg->len = popMessage->DLC; + + // TODO: use memcopy + for (int i = 0; i < msg->len; i++) { + msg->data[i] = obj->hcan->pRxMsg->Data[i]; + } + + result = msg->len; + + + +// printf("api: can_read: queueing up msg\r\n"); +// +// message_enqueue(obj, obj->hcan->pRxMsg); +// +// CanRxMsgTypeDef popMessage; +// if (message_dequeue (obj, &popMessage)) { +// /* result = 0; *//* redundant, but reinforce */ +// } else { +// +// msg->id = popMessage.IDE == CAN_ID_STD ? popMessage.StdId : popMessage.ExtId; +// msg->type = popMessage.RTR == CAN_RTR_DATA ? CANData : CANRemote; +// msg->format = popMessage.IDE == CAN_ID_STD ? CANStandard : CANExtended; +// msg->len = popMessage.DLC; +// +// // TODO: use memcopy +// for (int i = 0; i < msg->len; i++) { +// msg->data[i] = obj->hcan->pRxMsg->Data[i]; +/// } +// +// result = msg->len; +// } + } + + return result; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int +can_mode (can_t *obj, + CanMode mode) +{ + int success = 0; + + switch(mode) { + case MODE_RESET: + success = HAL_ERROR; + break; + + case MODE_NORMAL: + obj->hcan->Init.Mode = CAN_MODE_NORMAL; + break; + + case MODE_SILENT: + obj->hcan->Init.Mode = CAN_MODE_SILENT; + break; + + case MODE_TEST_GLOBAL: + obj->hcan->Init.Mode = CAN_MODE_LOOPBACK; + break; + + case MODE_TEST_LOCAL: + obj->hcan->Init.Mode = CAN_MODE_LOOPBACK; + break; + + case MODE_TEST_SILENT: + obj->hcan->Init.Mode = CAN_MODE_SILENT_LOOPBACK; + break; + } + + if (success != HAL_ERROR) { + success = HAL_CAN_Init(obj->hcan); + } + + return success; +} + +/** + * @brief + * @note + * @param + * @retval + */ +int +can_filter (can_t *obj, + uint32_t id, + uint32_t mask, + CANFormat format, + int32_t handle) +{ + 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(obj->hcan, &sFilterConfig); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_reset (can_t *obj) +{ + __HAL_CAN_RESET_HANDLE_STATE(obj->hcan); +} + +/** + * @brief + * @note + * @param + * @retval + */ +unsigned char +can_rderror (can_t *obj) +{ + return HAL_CAN_GetError(obj->hcan); +} + +/** + * @brief + * @note + * @param + * @retval + */ +unsigned char +can_tderror (can_t *obj) +{ + return HAL_CAN_GetError(obj->hcan); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void +can_monitor (can_t *obj, + int silent) +{ + // TODO: implement +} + +/*============================================================================= + * HAL_MSP and other functions + *============================================================================= + */ + +/** + * @brief F0 low level Initialization + * @retval None + */ +void HAL_MspInit(void) +{ + // DEBUG + printf("Msp: HAL_MspInit\r\n"); + + /* derived from STM32CubeMX */ + + __SYSCFG_CLK_ENABLE(); + + /* System interrupt init*/ + /* SysTick_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); +} + +/** + * @brief CAN MSP Initialization + * @param hcan: CAN handle pointer + * @retval None + */ +void +HAL_CAN_MspInit(CAN_HandleTypeDef* hcan) +{ + // DEBUG + printf("Msp: HAL_CAN_MspInit\r\n"); + + /* derived from STM32CubeMX */ + + GPIO_InitTypeDef GPIO_InitStruct; + if (hcan->Instance == ((CAN_TypeDef *) CAN_BASE)) { + if ((pinRd == PA_11) && (pinTd == PA_12)) { + + /* Peripheral clock enable */ + __CAN_CLK_ENABLE(); + + /* Enable GPIO clock */ + __GPIOA_CLK_ENABLE(); + + /**CAN GPIO Configuration + PA11 ------> CAN_RX + PA12 ------> CAN_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_CAN; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + } else if ((pinRd == PB_8) && (pinTd == PB_9)) { + /* Peripheral clock enable */ + __CAN_CLK_ENABLE(); + + /* Enable GPIO clock */ + __GPIOB_CLK_ENABLE(); + + /**CAN GPIO Configuration + PB8 ------> CAN_RX + PB9 ------> CAN_TX + */ + GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_CAN; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + } else { + printf("bad pins defined in CAN class\r\n"); + } + + /* Peripheral interrupt init*/ + HAL_NVIC_SetPriority(CEC_CAN_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(CEC_CAN_IRQn); + + } else { + printf("CAN_HandleTypeDef instance bad\r\n"); + } + +} + +/** + * @brief CAN MSP De-Initialization + * This function frees the hardware resources used: + * - Disable the Peripheral's clock + * - Revert GPIO to their default state + * @param hcan: CAN handle pointer + * @retval None + */ +void +HAL_CAN_MspDeInit (CAN_HandleTypeDef* hcan) +{ + // DEBUG + printf("Msp: HAL_CAN_MspDeInit\r\n"); + + /* derived from STM32CubeMX */ + + if (hcan->Instance == ((CAN_TypeDef *) CAN_BASE)) { + /* Peripheral clock disable */ + __CAN_CLK_DISABLE(); + + /* Disable pins*/ + if ((pinRd == PA_11) && (pinTd == PA_12)) { + /**CAN GPIO Configuration + PA11 ------> CAN_RX + PA12 ------> CAN_TX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12); + } else if ((pinRd == PB_8) && (pinTd == PB_9)) { + /**CAN GPIO Configuration + PB8 ------> CAN_RX + PB9 ------> CAN_TX + */ + HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8|GPIO_PIN_9); + } else {} + } + + /* Disable the NVIC for CAN reception */ + HAL_NVIC_DisableIRQ(CEC_CAN_IRQn); +} + +/** + * @brief Reception complete callback in non blocking mode + * @param obj->hcan: pointer to a CAN_HandleTypeDef structure that contains + * the configuration information for the specified CAN. + * @retval None + */ +void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan) +{ + /* Add message we jsut received to the can_message_queue */ + /* cheats and uses global pointer to the only can_t used for STM32 F0 */ + message_enqueue(single_can_controller, hcan->pRxMsg); + + /* Call user callback */ + irq_handler (can_irq_ids[0], IRQ_RX); + + + + // BUG: CAN race condition if HAL_CAN_Receive_IT() is used. + // See https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Java/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2FSTM32Java%2FBUG%20CAN%20race%20condition%20if%20HAL%5FCAN%5FReceive%5FIT%20is%20used + // + // Fixed by Mark Burton: + // ideally, we should be able to call HAL_CAN_Receive_IT() here to set up for another + // receive but the API is flawed because that function will fail if HAL_CAN_Transmit() + // had already locked the handle when the receive interrupt occurred - so we do what + // HAL_CAN_Receive_IT() would do + + /* + /* perform HAL_CAN_Receive_IT() fix * + if (hcan->State == HAL_CAN_STATE_BUSY_TX) { + hcan->State = HAL_CAN_STATE_BUSY_TX_RX; + } else { + hcan->State = HAL_CAN_STATE_BUSY_RX; + + /* Set CAN error code to none * + hcan->ErrorCode = HAL_CAN_ERROR_NONE; + /* Enable Error warning Interrupt * + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EWG); + /* Enable Error passive Interrupt * + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EPV); + /* Enable Bus-off Interrupt * + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_BOF); + /* Enable Last error code Interrupt * + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_LEC); + /* Enable Error Interrupt * + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_ERR); + } + + // Enable FIFO 0 message pending Interrupt + __HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0); + */ + + // try with standard call + //if (HAL_CAN_Receive_IT (hcan, CAN_FIFO0) != HAL_OK) { + // printf("api: can_irq_init: receive failed\r\n"); + //} + +} \ No newline at end of file