890 lines
28 KiB
C
890 lines
28 KiB
C
/*
|
|
* Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* o Redistributions of source code must retain the above copyright notice, this list
|
|
* of conditions and the following disclaimer.
|
|
*
|
|
* o 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.
|
|
*
|
|
* o Neither the name of Freescale Semiconductor, Inc. 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.
|
|
*/
|
|
|
|
#include "host_hardware.h"
|
|
#include "fsl_device_registers.h"
|
|
#include "port/fsl_port.h"
|
|
#include "flexcan/fsl_flexcan.h"
|
|
#include "dspi/fsl_dspi.h"
|
|
#include "uart/fsl_uart.h"
|
|
#include "i2c/fsl_i2c.h"
|
|
#include "utilities/fsl_rtos_abstraction.h"
|
|
|
|
#include "pin_mux.h"
|
|
#include "board.h"
|
|
#include "disk.h"
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
#define k_uartBufferSize 256
|
|
#define HOST_UART_INSTANCE 2
|
|
|
|
/*!
|
|
* @brief Internal driver state information.
|
|
*
|
|
* @note The contents of this structure are internal to the driver and should not be
|
|
* modified by users. Also, contents of the structure are subject to change in
|
|
* future releases.
|
|
*/
|
|
typedef struct FlexCANState
|
|
{
|
|
volatile uint32_t rx_mb_idx; /*!< Index of the message buffer for receiving*/
|
|
volatile uint32_t tx_mb_idx; /*!< Index of the message buffer for transmitting*/
|
|
semaphore_t txIrqSync; /*!< Used to wait for ISR to complete its TX business.*/
|
|
semaphore_t rxIrqSync; /*!< Used to wait for ISR to complete its RX business.*/
|
|
} flexcan_state_t;
|
|
|
|
/*! @brief FlexCAN data info from user*/
|
|
typedef struct FlexCANDataInfo
|
|
{
|
|
flexcan_frame_format_t msg_id_type; /*!< Type of message ID (standard or extended)*/
|
|
uint32_t data_length; /*!< Length of Data in Bytes*/
|
|
} flexcan_data_info_t;
|
|
|
|
/*! @brief FlexCAN operation modes*/
|
|
typedef enum _flexcan_operation_modes
|
|
{
|
|
kFlexCanNormalMode, /*!< Normal mode or user mode*/
|
|
kFlexCanListenOnlyMode, /*!< Listen-only mode*/
|
|
kFlexCanLoopBackMode, /*!< Loop-back mode*/
|
|
kFlexCanFreezeMode, /*!< Freeze mode*/
|
|
kFlexCanDisableMode, /*!< Module disable mode*/
|
|
} flexcan_operation_modes_t;
|
|
|
|
/*!
|
|
* @brief flexCAN common information structure
|
|
*/
|
|
typedef struct _flexcan_transfer_info
|
|
{
|
|
flexcan_state_t state; //!< state
|
|
flexcan_data_info_t rx_info; //!< tx info
|
|
flexcan_data_info_t tx_info; //!< tx info
|
|
uint32_t rxId; //!< rx id
|
|
uint32_t txId; //!< tx id
|
|
uint32_t rx_mailbox_num; //!< rx mb number
|
|
uint32_t tx_mailbox_num; //!< tx mb number
|
|
uint8_t rx_buf[64]; //!< rx buffer
|
|
uint8_t rx_buf_write_index; //!< rx buffer write index
|
|
uint8_t rx_buf_read_index; //!< rx buffer read index
|
|
} flexcan_transfer_info_t;
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
/*!
|
|
* @brief uart byte receive callback.
|
|
*/
|
|
static void s_uart_byte_receive_callback(uint8_t byte);
|
|
|
|
/*!
|
|
* @brief I2C transfer callback.
|
|
*/
|
|
static void i2c_master_callback(I2C_Type *base, i2c_master_handle_t *handle, status_t status, void *userData);
|
|
|
|
/*!
|
|
* @brief Return specified UART clock, LPUART0 is not supported here.
|
|
*/
|
|
static uint32_t get_uart_clock(uint32_t instance);
|
|
|
|
/*! @brief init uart functions. */
|
|
static void init_suarts(void);
|
|
|
|
/*! @brief dspi initialization. */
|
|
static void init_dspi(void);
|
|
|
|
/*! @brief i2c initialization. */
|
|
static void init_i2c(uint32_t instance);
|
|
|
|
/*! @brief flexcan initialization. */
|
|
static void init_flexcan(void);
|
|
|
|
static void read_can_data(uint8_t data, uint32_t instance);
|
|
|
|
static status_t FLEXCAN_Send(uint8_t instance,
|
|
uint32_t mb_idx,
|
|
flexcan_data_info_t *tx_info,
|
|
uint32_t msg_id,
|
|
uint8_t *mb_data,
|
|
uint32_t timeout_ms);
|
|
|
|
//! @brief flexCAN reset buffer process
|
|
static void reset_can_buffer(void);
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
|
|
/*! @brief Variable for DSPI setup information */
|
|
static dspi_master_config_t g_dspiConfig;
|
|
static dspi_transfer_t g_dspi_masterXfer;
|
|
const static uint32_t g_dspiBaseAddr[] = SPI_BASE_ADDRS;
|
|
dspi_master_handle_t g_dspi_masterHandle;
|
|
|
|
/*! @brief Variable for I2C setup information */
|
|
static i2c_master_config_t s_i2cMasterConfig;
|
|
static i2c_master_transfer_t s_i2c_masterXfer;
|
|
const static uint32_t g_i2cBaseAddr[] = I2C_BASE_ADDRS;
|
|
i2c_master_handle_t g_i2c_masterHandle = { 0 };
|
|
volatile bool g_I2C_MasterCompletionFlag = false;
|
|
|
|
/* Uart1 */
|
|
static uint8_t *s_uart_rxData;
|
|
static uint32_t s_uart_bytesRx;
|
|
/* Uart1 buffer */
|
|
static uint8_t s_uartBuffer[k_uartBufferSize];
|
|
static uint8_t *s_uartPtr = s_uartBuffer;
|
|
static uint32_t s_uartBufferOffset = 0;
|
|
|
|
/* Array of UART peripheral base address. */
|
|
static UART_Type *const s_uartBase[] = UART_BASE_PTRS;
|
|
/* Array of UART IRQ number. */
|
|
static const IRQn_Type s_uartIRQ[] = UART_RX_TX_IRQS;
|
|
|
|
/* FlexCan */
|
|
const static uint32_t g_flexcanBaseAddr[] = CAN_BASE_ADDRS;
|
|
|
|
/* Tables to save CAN IRQ enum numbers defined in CMSIS header file. */
|
|
const IRQn_Type g_flexcanRxWarningIrqId[] = CAN_Rx_Warning_IRQS;
|
|
const IRQn_Type g_flexcanTxWarningIrqId[] = CAN_Tx_Warning_IRQS;
|
|
const IRQn_Type g_flexcanWakeUpIrqId[] = CAN_Wake_Up_IRQS;
|
|
const IRQn_Type g_flexcanErrorIrqId[] = CAN_Error_IRQS;
|
|
const IRQn_Type g_flexcanBusOffIrqId[] = CAN_Bus_Off_IRQS;
|
|
const IRQn_Type g_flexcanOredMessageBufferIrqId[] = CAN_ORed_Message_buffer_IRQS;
|
|
|
|
/*!
|
|
* @brief flexCAN timing table (120Mhz)contains propseg, pseg1, pseg2, pre_divider, rjw
|
|
*/
|
|
flexcan_timing_config_t bit_rate_table[] = {
|
|
{ 47, 1, 3, 2, 1 }, /* 125 kHz */
|
|
{ 23, 1, 3, 2, 1 }, /* 250 kHz */
|
|
{ 11, 1, 3, 2, 1 }, /* 500 kHz */
|
|
{ 7, 1, 3, 2, 1 }, /* 750 kHz */
|
|
{ 5, 1, 3, 2, 1 }, /* 1 MHz */
|
|
};
|
|
|
|
/*!
|
|
* @brief flexCAN instance used for bus pal
|
|
*/
|
|
uint8_t flexcanInstance = 0;
|
|
|
|
//! @brief Global state for the FlexCAN peripheral interface.
|
|
flexcan_transfer_info_t s_flexcanInfo;
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
void hardware_init(void)
|
|
{
|
|
uint32_t count = 0;
|
|
uint32_t regPrimask = 0U;
|
|
|
|
/* Disable the MPU otherwise USB cannot access the bus */
|
|
MPU->CESR = 0;
|
|
|
|
BOARD_InitPins();
|
|
BOARD_InitLED();
|
|
BOARD_InitSwitch();
|
|
|
|
microseconds_init();
|
|
init_suarts();
|
|
init_dspi();
|
|
init_flexcan();
|
|
init_i2c(I2C_INSTANCE);
|
|
|
|
/* Wait to hardware stable */
|
|
microseconds_delay(500000);
|
|
microseconds_shutdown();
|
|
|
|
for (uint32_t i = 0; i < 100; i++)
|
|
{
|
|
if (BOARD_ReadSwitch(kSwitch3))
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
if (count > 60)
|
|
{
|
|
disk_init();
|
|
FLASH_Init(&s_flashInstance);
|
|
|
|
/* Disable IRQ, protect ring buffer. */
|
|
regPrimask = __get_PRIMASK();
|
|
__disable_irq();
|
|
|
|
/* 1M flash region to store flash image */
|
|
FLASH_Erase(&s_flashInstance, MSD_FLASH_BASE, 1024 * 1024, kFLASH_ApiEraseKey);
|
|
|
|
/* Recover PRIMASK, enable IRQ if previously enabled. */
|
|
__set_PRIMASK(regPrimask);
|
|
}
|
|
|
|
PORT_SetPinInterruptConfig(BOARD_SW2_PORT, BOARD_SW2_GPIO_PIN, kPORT_InterruptFallingEdge);
|
|
EnableIRQ(BOARD_SW2_IRQ);
|
|
PORT_SetPinInterruptConfig(BOARD_SW3_PORT, BOARD_SW3_GPIO_PIN, kPORT_InterruptFallingEdge);
|
|
EnableIRQ(BOARD_SW3_IRQ);
|
|
}
|
|
|
|
uint32_t get_bus_clock(void)
|
|
{
|
|
uint32_t busClockDivider = ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT) + 1;
|
|
return (SystemCoreClock / busClockDivider);
|
|
}
|
|
|
|
uint32_t get_fast_peripheral_clock(void)
|
|
{
|
|
uint32_t busClockDivider = ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT) + 1;
|
|
return (SystemCoreClock / busClockDivider);
|
|
}
|
|
|
|
bool usb_clock_init(void)
|
|
{
|
|
SIM->CLKDIV2 = (uint32_t)0x0UL; /* Update USB clock prescalers */
|
|
/* Select MCGPLLCLK clock */
|
|
SIM->SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
|
|
SIM->SOPT2 |= (SIM_SOPT2_USBSRC_MASK | SIM_SOPT2_PLLFLLSEL(0x01U));
|
|
SIM->CLKDIV2 = (uint32_t)0x09UL; /* Update USB clock prescalers */
|
|
/* Enable USB-OTG IP clocking */
|
|
SIM->SCGC4 |= (SIM_SCGC4_USBOTG_MASK);
|
|
|
|
/* Configure enable USB regulator for device */
|
|
SIM->SOPT1 |= SIM_SOPT1_USBREGEN_MASK;
|
|
/* SIM_SOPT1: OSC32KSEL=0 */
|
|
SIM->SOPT1 &=
|
|
(uint32_t)~SIM_SOPT1_OSC32KSEL_MASK; /* System oscillator drives 32 kHz clock for various peripherals */
|
|
|
|
return true;
|
|
}
|
|
|
|
static void init_suarts(void)
|
|
{
|
|
/* UART2 for OpenSDA and UART4 for Kibble */
|
|
uart_config_t config;
|
|
|
|
UART_GetDefaultConfig(&config);
|
|
config.baudRate_Bps = kUART_DEFAULT_BAUD;
|
|
config.enableTx = true;
|
|
config.enableRx = true;
|
|
|
|
UART_Init(s_uartBase[HOST_UART_INSTANCE], &config, get_uart_clock(HOST_UART_INSTANCE));
|
|
|
|
EnableIRQ(s_uartIRQ[UART_INSTANCE]);
|
|
UART_Init(s_uartBase[UART_INSTANCE], &config, get_uart_clock(UART_INSTANCE));
|
|
UART_EnableInterrupts(s_uartBase[UART_INSTANCE], kUART_RxDataRegFullInterruptEnable);
|
|
}
|
|
|
|
static uint32_t get_uart_clock(uint32_t instance)
|
|
{
|
|
switch (instance)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
/* UART0 and UART1 always use the system clock */
|
|
return SystemCoreClock;
|
|
case 2:
|
|
return get_bus_clock();
|
|
case 3:
|
|
case 4:
|
|
/* UART2-4 always use the bus clock. */
|
|
return get_bus_clock();
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void init_dspi(void)
|
|
{
|
|
uint32_t baseAddr = g_dspiBaseAddr[SPI_INSTANCE];
|
|
|
|
DSPI_MasterGetDefaultConfig(&g_dspiConfig);
|
|
g_dspiConfig.whichCtar = kDSPI_Ctar1;
|
|
g_dspiConfig.ctarConfig.cpol = kDSPI_ClockPolarityActiveLow;
|
|
g_dspiConfig.ctarConfig.cpha = kDSPI_ClockPhaseSecondEdge;
|
|
g_dspiConfig.ctarConfig.baudRate = 100000U;
|
|
|
|
DSPI_MasterInit((SPI_Type *)baseAddr, &g_dspiConfig, get_bus_clock());
|
|
|
|
g_dspi_masterXfer.configFlags = kDSPI_MasterCtar1 | kDSPI_MasterPcs0 | kDSPI_MasterPcsContinuous;
|
|
}
|
|
|
|
static void init_i2c(uint32_t instance)
|
|
{
|
|
I2C_MasterGetDefaultConfig(&s_i2cMasterConfig);
|
|
|
|
I2C_MasterInit((I2C_Type *)g_i2cBaseAddr[instance], &s_i2cMasterConfig, get_bus_clock());
|
|
I2C_MasterTransferCreateHandle((I2C_Type *)g_i2cBaseAddr[instance], &g_i2c_masterHandle, i2c_master_callback, NULL);
|
|
|
|
s_i2c_masterXfer.slaveAddress = 0x10;
|
|
s_i2c_masterXfer.subaddress = 0;
|
|
s_i2c_masterXfer.subaddressSize = 0;
|
|
s_i2c_masterXfer.flags = kI2C_TransferDefaultFlag;
|
|
}
|
|
|
|
static void init_flexcan(void)
|
|
{
|
|
flexcan_config_t config;
|
|
uint32_t baseAddr = g_flexcanBaseAddr[FLEXCAN_INSTANCE];
|
|
|
|
FLEXCAN_GetDefaultConfig(&config);
|
|
config.clkSrc = kFLEXCAN_ClkSrcPeri;
|
|
config.baudRate = 125000;
|
|
|
|
/* Select mailbox number */
|
|
s_flexcanInfo.rx_mailbox_num = 8;
|
|
s_flexcanInfo.tx_mailbox_num = 9;
|
|
|
|
/* make bootloader as node 'b' for testing */
|
|
s_flexcanInfo.rxId = 0x123;
|
|
s_flexcanInfo.txId = 0x321;
|
|
|
|
s_flexcanInfo.rx_buf_write_index = 0;
|
|
s_flexcanInfo.rx_buf_read_index = 0;
|
|
|
|
/* Init the interrupt sync object.*/
|
|
OSA_SemaCreate(&s_flexcanInfo.state.txIrqSync, 0);
|
|
OSA_SemaCreate(&s_flexcanInfo.state.rxIrqSync, 0);
|
|
s_flexcanInfo.state.rx_mb_idx = 8;
|
|
s_flexcanInfo.state.tx_mb_idx = 9;
|
|
|
|
/* also need to get clock selection config data */
|
|
FLEXCAN_Init((CAN_Type *)baseAddr, &config, get_bus_clock());
|
|
|
|
FLEXCAN_Enable((CAN_Type *)baseAddr, true);
|
|
|
|
FLEXCAN_EnableInterrupts((CAN_Type *)baseAddr, kFLEXCAN_ErrorInterruptEnable);
|
|
|
|
/* using setting table */
|
|
FLEXCAN_SetTimingConfig((CAN_Type *)baseAddr, &bit_rate_table[0]);
|
|
|
|
/* FlexCAN reveive config */
|
|
s_flexcanInfo.rx_info.msg_id_type = kFLEXCAN_FrameFormatStandard;
|
|
s_flexcanInfo.rx_info.data_length = 8;
|
|
|
|
/* Configure RX MB fields */
|
|
flexcan_rx_mb_config_t mbConfig;
|
|
mbConfig.format = kFLEXCAN_FrameFormatStandard;
|
|
mbConfig.id = CAN_ID_STD(s_flexcanInfo.rxId);
|
|
mbConfig.type = kFLEXCAN_FrameTypeData;
|
|
FLEXCAN_SetRxMbConfig((CAN_Type *)baseAddr, 8, &mbConfig, true);
|
|
|
|
FLEXCAN_EnableMbInterrupts((CAN_Type *)baseAddr, 1 << 8);
|
|
|
|
/* FlexCAN transfer config */
|
|
s_flexcanInfo.tx_info.msg_id_type = kFLEXCAN_FrameFormatStandard;
|
|
s_flexcanInfo.tx_info.data_length = 8;
|
|
|
|
FLEXCAN_SetTxMbConfig((CAN_Type *)baseAddr, 9, false);
|
|
|
|
NVIC_EnableIRQ(g_flexcanErrorIrqId[FLEXCAN_INSTANCE]);
|
|
NVIC_EnableIRQ(g_flexcanBusOffIrqId[FLEXCAN_INSTANCE]);
|
|
NVIC_EnableIRQ(g_flexcanOredMessageBufferIrqId[FLEXCAN_INSTANCE]);
|
|
}
|
|
|
|
bool wait_uart_char(uint8_t *data)
|
|
{
|
|
/* If has data */
|
|
if (s_uartBase[HOST_UART_INSTANCE]->RCFIFO)
|
|
{
|
|
*data = UART_ReadByte(s_uartBase[HOST_UART_INSTANCE]);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
uint8_t wait_uart_char_blocking(void)
|
|
{
|
|
uint8_t byte = 0;
|
|
|
|
UART_ReadBlocking(s_uartBase[HOST_UART_INSTANCE], &byte, 1);
|
|
|
|
return byte;
|
|
}
|
|
|
|
void configure_spi_speed(uint32_t speedkhz)
|
|
{
|
|
uint32_t bitsPerSec = speedkhz * 1000;
|
|
DSPI_MasterSetBaudRate((SPI_Type *)g_dspiBaseAddr[SPI_INSTANCE], kDSPI_Ctar1, bitsPerSec, get_bus_clock());
|
|
}
|
|
|
|
status_t send_spi_data(uint8_t *src, uint32_t writeLength)
|
|
{
|
|
g_dspi_masterXfer.txData = src;
|
|
g_dspi_masterXfer.rxData = NULL;
|
|
g_dspi_masterXfer.dataSize = writeLength;
|
|
|
|
DSPI_MasterTransferBlocking((SPI_Type *)g_dspiBaseAddr[SPI_INSTANCE], &g_dspi_masterXfer);
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
status_t receive_spi_data(uint8_t *dest, uint32_t readLength)
|
|
{
|
|
g_dspi_masterXfer.txData = NULL;
|
|
g_dspi_masterXfer.rxData = dest;
|
|
g_dspi_masterXfer.dataSize = readLength;
|
|
|
|
DSPI_MasterTransferBlocking((SPI_Type *)g_dspiBaseAddr[SPI_INSTANCE], &g_dspi_masterXfer);
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
void configure_i2c_speed(uint32_t speedkhz)
|
|
{
|
|
I2C_MasterSetBaudRate((I2C_Type *)g_i2cBaseAddr[I2C_INSTANCE], speedkhz * 1000, get_bus_clock());
|
|
}
|
|
|
|
status_t send_i2c_data(uint8_t *src, uint32_t writeLength)
|
|
{
|
|
s_i2c_masterXfer.direction = kI2C_Write;
|
|
s_i2c_masterXfer.data = src;
|
|
s_i2c_masterXfer.dataSize = writeLength;
|
|
|
|
I2C_MasterTransferBlocking((I2C_Type *)g_i2cBaseAddr[I2C_INSTANCE], &s_i2c_masterXfer);
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
static void i2c_master_callback(I2C_Type *base, i2c_master_handle_t *handle, status_t status, void *userData)
|
|
{
|
|
/* Signal transfer success when received success status. */
|
|
if (status == kStatus_Success)
|
|
{
|
|
g_I2C_MasterCompletionFlag = true;
|
|
}
|
|
}
|
|
|
|
status_t receive_i2c_data(uint8_t *dest, uint32_t readLength)
|
|
{
|
|
uint16_t timeout = UINT16_MAX;
|
|
|
|
s_i2c_masterXfer.direction = kI2C_Read;
|
|
s_i2c_masterXfer.data = dest;
|
|
s_i2c_masterXfer.dataSize = readLength;
|
|
|
|
I2C_MasterTransferNonBlocking((I2C_Type *)g_i2cBaseAddr[I2C_INSTANCE], &g_i2c_masterHandle, &s_i2c_masterXfer);
|
|
|
|
/* Reset master completion flag to false. */
|
|
g_I2C_MasterCompletionFlag = false;
|
|
|
|
/* Wait for transfer completed. */
|
|
while ((!g_I2C_MasterCompletionFlag) && (--timeout))
|
|
{
|
|
}
|
|
if (timeout == 0)
|
|
{
|
|
return kStatus_Timeout;
|
|
}
|
|
|
|
g_I2C_MasterCompletionFlag = false;
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
void configure_can_speed(uint32_t speedkhz)
|
|
{
|
|
/* Just support 125K, 250K, 500K, 750K, and 1000K */
|
|
uint32_t speed_index = 0;
|
|
|
|
switch (speedkhz)
|
|
{
|
|
case kFLEXCAN_125K:
|
|
speed_index = 0;
|
|
break;
|
|
case kFLEXCAN_250K:
|
|
speed_index = 1;
|
|
break;
|
|
case kFLEXCAN_500K:
|
|
speed_index = 2;
|
|
break;
|
|
case kFLEXCAN_750K:
|
|
speed_index = 3;
|
|
break;
|
|
case kFLEXCAN_1000K:
|
|
speed_index = 4;
|
|
break;
|
|
}
|
|
|
|
if (speed_index < 5)
|
|
{
|
|
/* using setting table */
|
|
FLEXCAN_SetTimingConfig((CAN_Type *)g_flexcanBaseAddr[FLEXCAN_INSTANCE], &bit_rate_table[speed_index]);
|
|
}
|
|
}
|
|
|
|
status_t send_can_data(uint8_t *src, uint32_t writeLength)
|
|
{
|
|
uint32_t sentCnt = 0;
|
|
uint8_t *sendPtr = src;
|
|
|
|
while (sentCnt < writeLength)
|
|
{
|
|
if ((writeLength - sentCnt) <= 8)
|
|
{
|
|
/* number of bytes to be sent */
|
|
s_flexcanInfo.tx_info.data_length = writeLength - sentCnt;
|
|
sentCnt += writeLength - sentCnt;
|
|
}
|
|
else
|
|
{
|
|
/* number of bytes to be sent */
|
|
s_flexcanInfo.tx_info.data_length = 8;
|
|
sentCnt += 8;
|
|
}
|
|
|
|
FLEXCAN_Send(FLEXCAN_INSTANCE, 9, &s_flexcanInfo.tx_info, s_flexcanInfo.txId, (uint8_t *)sendPtr, 1000);
|
|
|
|
sendPtr += s_flexcanInfo.tx_info.data_length;
|
|
}
|
|
|
|
reset_can_buffer();
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
status_t FLEXCAN_Send(uint8_t instance,
|
|
uint32_t mb_idx,
|
|
flexcan_data_info_t *tx_info,
|
|
uint32_t msg_id,
|
|
uint8_t *mb_data,
|
|
uint32_t timeout_ms)
|
|
{
|
|
uint32_t baseAddr = g_flexcanBaseAddr[instance];
|
|
osa_status_t syncStatus;
|
|
uint8_t i;
|
|
flexcan_frame_t frame;
|
|
flexcan_mb_transfer_t xfer;
|
|
xfer.mbIdx = mb_idx;
|
|
frame.format = tx_info->msg_id_type;
|
|
frame.length = tx_info->data_length;
|
|
frame.id = CAN_ID_STD(msg_id);
|
|
frame.type = kFLEXCAN_FrameTypeData;
|
|
xfer.frame = &frame;
|
|
|
|
/* Copy user's buffer into the message buffer data area*/
|
|
if (mb_data != NULL)
|
|
{
|
|
xfer.frame->dataWord0 = 0x0;
|
|
xfer.frame->dataWord1 = 0x0;
|
|
|
|
for (i = 0; i < tx_info->data_length; i++)
|
|
{
|
|
uint32_t temp, temp1;
|
|
temp1 = (*(mb_data + i));
|
|
if (i < 4)
|
|
{
|
|
temp = temp1 << ((3 - i) * 8);
|
|
xfer.frame->dataWord0 |= temp;
|
|
}
|
|
else
|
|
{
|
|
temp = temp1 << ((7 - i) * 8);
|
|
xfer.frame->dataWord1 |= temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kStatus_Success == FLEXCAN_WriteTxMb((CAN_Type *)baseAddr, mb_idx, xfer.frame))
|
|
{
|
|
/* Enable Message Buffer Interrupt. */
|
|
FLEXCAN_EnableMbInterrupts((CAN_Type *)baseAddr, 1 << mb_idx);
|
|
|
|
do
|
|
{
|
|
syncStatus = OSA_SemaWait(&s_flexcanInfo.state.txIrqSync, timeout_ms);
|
|
} while (syncStatus == kStatus_OSA_Idle);
|
|
|
|
/* Disable message buffer interrupt*/
|
|
FLEXCAN_DisableMbInterrupts((CAN_Type *)baseAddr, 1 << mb_idx);
|
|
|
|
/* Wait for the interrupt*/
|
|
if (syncStatus != kStatus_OSA_Success)
|
|
{
|
|
return kStatus_Timeout;
|
|
}
|
|
else
|
|
{
|
|
return kStatus_Success;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return kStatus_Fail;
|
|
}
|
|
}
|
|
|
|
void FLEXCAN_IRQHandler(uint8_t instance)
|
|
{
|
|
volatile uint32_t flag_reg;
|
|
uint32_t temp;
|
|
CAN_Type *baseAddr = (CAN_Type *)g_flexcanBaseAddr[instance];
|
|
|
|
/* Get the interrupts that are enabled and ready */
|
|
flag_reg = (baseAddr->IFLAG1 & baseAddr->IMASK1);
|
|
|
|
/* Check Tx/Rx interrupt flag and clear the interrupt */
|
|
if (flag_reg)
|
|
{
|
|
temp = (1 << s_flexcanInfo.state.rx_mb_idx);
|
|
if (flag_reg & temp)
|
|
{
|
|
OSA_SemaPost(&s_flexcanInfo.state.rxIrqSync);
|
|
|
|
flexcan_frame_t rxFrame;
|
|
/* Get RX MB field values*/
|
|
if (!FLEXCAN_ReadRxMb(baseAddr, s_flexcanInfo.state.rx_mb_idx, &rxFrame))
|
|
{
|
|
uint8_t i;
|
|
uint8_t sink_byte = 0;
|
|
for (i = 0; i < rxFrame.length; i++)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
sink_byte = rxFrame.dataByte0;
|
|
break;
|
|
case 1:
|
|
sink_byte = rxFrame.dataByte1;
|
|
break;
|
|
case 2:
|
|
sink_byte = rxFrame.dataByte2;
|
|
break;
|
|
case 3:
|
|
sink_byte = rxFrame.dataByte3;
|
|
break;
|
|
case 4:
|
|
sink_byte = rxFrame.dataByte4;
|
|
break;
|
|
case 5:
|
|
sink_byte = rxFrame.dataByte5;
|
|
break;
|
|
case 6:
|
|
sink_byte = rxFrame.dataByte6;
|
|
break;
|
|
case 7:
|
|
sink_byte = rxFrame.dataByte7;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
read_can_data(sink_byte, instance);
|
|
}
|
|
}
|
|
}
|
|
|
|
temp = (1 << s_flexcanInfo.state.tx_mb_idx);
|
|
if (flag_reg & temp)
|
|
{
|
|
OSA_SemaPost(&s_flexcanInfo.state.txIrqSync);
|
|
}
|
|
|
|
baseAddr->IFLAG1 = flag_reg;
|
|
}
|
|
|
|
/* Clear all other interrupts in ERRSTAT register (Error, Busoff, Wakeup) */
|
|
FLEXCAN_ClearStatusFlags(baseAddr, kFLEXCAN_ErrorFlag | CAN_ESR1_ERRINT_MASK);
|
|
|
|
return;
|
|
}
|
|
|
|
/*FUNCTION**********************************************************************
|
|
*
|
|
* Function Name : FLEXCAN_IRQBusoffHandler
|
|
* Description : Busoff interrupt handler
|
|
*
|
|
*END**************************************************************************/
|
|
void FLEXCAN_IRQBusoffHandler(uint8_t instance)
|
|
{
|
|
uint32_t baseAddr = g_flexcanBaseAddr[instance];
|
|
FLEXCAN_ClearStatusFlags((CAN_Type *)baseAddr, kFLEXCAN_ErrorFlag | CAN_ESR1_ERRINT_MASK);
|
|
}
|
|
|
|
/*FUNCTION**********************************************************************
|
|
*
|
|
* Function Name : FLEXCAN_DRV_IRQ_Error_Handler
|
|
* Description : flexCAN general error interrupt handler
|
|
*
|
|
*END**************************************************************************/
|
|
void FLEXCAN_IRQErrorHandler(uint8_t instance)
|
|
{
|
|
uint32_t baseAddr = g_flexcanBaseAddr[instance];
|
|
FLEXCAN_ClearStatusFlags((CAN_Type *)baseAddr, kFLEXCAN_ErrorFlag | CAN_ESR1_ERRINT_MASK);
|
|
}
|
|
|
|
/*FUNCTION**********************************************************************
|
|
*
|
|
* Function Name : receive_can_data
|
|
* Description : flexCAN receiving data process
|
|
*
|
|
*END**************************************************************************/
|
|
static void read_can_data(uint8_t data, uint32_t instance)
|
|
{
|
|
s_flexcanInfo.rx_buf[s_flexcanInfo.rx_buf_write_index++] = data;
|
|
s_flexcanInfo.rx_buf_write_index &= 0x3f;
|
|
}
|
|
|
|
/*FUNCTION**********************************************************************
|
|
*
|
|
* Function Name : reset_can_buffer
|
|
* Description : flexCAN reset buffer process
|
|
*
|
|
*END**************************************************************************/
|
|
static void reset_can_buffer(void)
|
|
{
|
|
s_flexcanInfo.rx_buf_write_index = 0;
|
|
s_flexcanInfo.rx_buf_read_index = 0;
|
|
}
|
|
|
|
/*FUNCTION**********************************************************************
|
|
*
|
|
* Function Name : read_can_data
|
|
* Description : flexCAN read data process
|
|
*
|
|
*END**************************************************************************/
|
|
status_t receive_can_data(uint8_t *dest, uint32_t readLength)
|
|
{
|
|
uint8_t received_cnt = 0;
|
|
uint16_t timeout = UINT16_MAX;
|
|
|
|
while ((received_cnt < readLength) && (--timeout))
|
|
{
|
|
if (s_flexcanInfo.rx_buf_read_index != s_flexcanInfo.rx_buf_write_index)
|
|
{
|
|
dest[received_cnt++] = s_flexcanInfo.rx_buf[s_flexcanInfo.rx_buf_read_index++];
|
|
s_flexcanInfo.rx_buf_read_index &= 0x3f;
|
|
}
|
|
}
|
|
|
|
if (timeout == 0)
|
|
{
|
|
init_flexcan();
|
|
return kStatus_Timeout;
|
|
}
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
void configure_uart_speed(uint32_t baud)
|
|
{
|
|
uart_config_t config;
|
|
|
|
UART_GetDefaultConfig(&config);
|
|
config.baudRate_Bps = baud;
|
|
config.enableTx = true;
|
|
config.enableRx = true;
|
|
|
|
UART_Init(s_uartBase[UART_INSTANCE], &config, get_bus_clock());
|
|
}
|
|
|
|
status_t send_uart_data(uint8_t *src, uint32_t writeLength)
|
|
{
|
|
UART_WriteBlocking(s_uartBase[UART_INSTANCE], src, writeLength);
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
status_t receive_uart_data(uint8_t *dest, uint32_t readLength)
|
|
{
|
|
uint16_t timeout = UINT16_MAX;
|
|
|
|
while ((((s_uart_bytesRx + k_uartBufferSize - s_uartBufferOffset) % k_uartBufferSize) < readLength) && (--timeout))
|
|
{
|
|
}
|
|
|
|
if (timeout == 0)
|
|
{
|
|
return kStatus_Timeout;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < readLength; i++)
|
|
{
|
|
dest[i] = s_uartPtr[(s_uartBufferOffset + i) % k_uartBufferSize];
|
|
}
|
|
s_uartBufferOffset = (s_uartBufferOffset + sizeof(uint8_t) * readLength) % k_uartBufferSize;
|
|
|
|
return kStatus_Success;
|
|
}
|
|
|
|
void UART4_RX_TX_IRQHandler(void)
|
|
{
|
|
if (UART4->S1 & UART_S1_RDRF_MASK)
|
|
{
|
|
s_uart_byte_receive_callback(UART4->D);
|
|
}
|
|
}
|
|
|
|
static void s_uart_byte_receive_callback(uint8_t byte)
|
|
{
|
|
s_uart_rxData = s_uartPtr;
|
|
if (s_uart_rxData)
|
|
{
|
|
s_uart_rxData[s_uart_bytesRx] = byte;
|
|
s_uart_bytesRx = (s_uart_bytesRx + 1) % k_uartBufferSize;
|
|
}
|
|
s_uart_rxData = 0;
|
|
}
|
|
|
|
void CAN0_ORed_Message_buffer_IRQHandler(void)
|
|
{
|
|
FLEXCAN_IRQHandler(0);
|
|
}
|
|
|
|
/* Implementation of CAN0 handler named in startup code. */
|
|
void CAN0_Bus_Off_IRQHandler(void)
|
|
{
|
|
FLEXCAN_IRQBusoffHandler(0);
|
|
}
|
|
|
|
/* Implementation of CAN0 handler named in startup code. */
|
|
void CAN0_Error_IRQHandler(void)
|
|
{
|
|
FLEXCAN_IRQErrorHandler(0);
|
|
}
|
|
|
|
void CAN0_Wake_Up_IRQHandler(void)
|
|
{
|
|
FLEXCAN_IRQHandler(0);
|
|
}
|
|
|
|
#if __ICCARM__
|
|
|
|
size_t __write(int handle, const unsigned char *buf, size_t size)
|
|
{
|
|
while (size--)
|
|
{
|
|
UART_WriteBlocking(s_uartBase[HOST_UART_INSTANCE], (uint8_t const *)buf++, 1);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
#endif /* __ICCARM__ */
|