806 lines
29 KiB
C
806 lines
29 KiB
C
/**
|
|
* @file sdrv_sent.c
|
|
* @brief SemiDrive Sent driver source.
|
|
*
|
|
* @copyright Copyright (c) 2020 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include <checksum/crc4.h>
|
|
#include <compiler.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <types.h>
|
|
|
|
#include "sdrv_sent.h"
|
|
|
|
#include "debug.h"
|
|
#include "irq.h"
|
|
#include "sdrv_etimer_lld.h"
|
|
|
|
/* Global buffer for frame information. */
|
|
static sent_chan_frame_t g_frame_info[SDRV_SENT_CHAN_NUM];
|
|
|
|
/**************************Static Functions Start******************************/
|
|
/**
|
|
* brief Sdrv sent channel id map to etimer channel id.
|
|
*
|
|
* param [in] sent_chan_id Sent channel id
|
|
* param [out] etimer_cnt_id Sdrv etimer channel id
|
|
*/
|
|
|
|
static void sdrv_chanid_map(sdrv_sent_chanid_e sent_chan_id,
|
|
sdrv_etimer_cnt_id_e *etimer_cnt_id);
|
|
|
|
/**
|
|
* brief Sdrv sent module initialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
*/
|
|
static void sdrv_sent_module_init(sdrv_sent_t *ctrl);
|
|
|
|
/**
|
|
* brief Sdrv sent module deinitialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
*/
|
|
static void sdrv_sent_module_deinit(sdrv_sent_t *ctrl);
|
|
/**
|
|
* brief Sdrv sent channel initialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
* param [in] sent_chan_id Sent channel id
|
|
*/
|
|
static void sdrv_sent_channel_init(sdrv_sent_t *ctrl,
|
|
sdrv_sent_chanid_e sent_chan_id);
|
|
|
|
/**
|
|
* brief Sdrv sent channel deinitialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
* param [in] sent_chan_id Sent channel id
|
|
*/
|
|
static void sdrv_sent_channel_deinit(sdrv_sent_t *ctrl,
|
|
sdrv_sent_chanid_e sent_chan_id);
|
|
|
|
/**
|
|
* brief Parse data to tick.
|
|
*
|
|
* param [in] data data in dma fifo.
|
|
* param [in] actual_scaler sent channel actual scaler.
|
|
* return The count of tick.
|
|
*/
|
|
static uint32_t sdrv_tick_parse(uint32_t data, uint32_t actual_scaler);
|
|
|
|
/**
|
|
* brief Check the configurations of sent.
|
|
*
|
|
* param [in] cfg Sdrv sent configurations.
|
|
* return The configurations are valid or not.
|
|
* - true : The configurations of sent are valid.
|
|
* - false : The configurations of sent are unvalid.
|
|
*/
|
|
static bool sdrv_sent_config_check(sdrv_sent_config_t *cfg);
|
|
|
|
/**************************Static Functions End********************************/
|
|
/**
|
|
* @brief Sdrv sent controller initialization.
|
|
*
|
|
* This fuction initializes sent(etimer) module and channel and controller
|
|
* entity status.
|
|
*
|
|
* @param [in] ctrl Sdrv sent controller.
|
|
* @param [in] cfg Sdrv sent configurations.
|
|
* @return The result of initializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null
|
|
* pointer.
|
|
* - SDRV_STATUS_OK : Sent is initialized success.
|
|
*/
|
|
status_t sdrv_sent_init(sdrv_sent_t *ctrl, sdrv_sent_config_t *cfg)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (!sdrv_sent_config_check(cfg))) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
/* Sent module config and clock initialize. */
|
|
(void)memset(ctrl, 0, sizeof(sdrv_sent_t));
|
|
ctrl->base = cfg->base;
|
|
ctrl->irq = cfg->irq;
|
|
ctrl->chan_num = SDRV_SENT_CHAN_NUM;
|
|
ctrl->clk_sel = cfg->clk_sel;
|
|
ctrl->clk_freq = cfg->clk_freq;
|
|
ctrl->clk_div = cfg->clk_div;
|
|
/* Initialize sent(etimer) module . */
|
|
sdrv_sent_module_init(ctrl);
|
|
ctrl->sent_sta = SENT_STATUS_INITED;
|
|
|
|
/* Sent channel config and initialize. */
|
|
for (uint8_t i = 0; i < cfg->chan_cfg_num; ++i) {
|
|
sdrv_sent_chanid_e chan_id = cfg->chan_cfg[i].chan_id;
|
|
if (chan_id < SDRV_SENT_CHAN_NUM) {
|
|
sdrv_sent_chan_t *sdrv_sent_chan = &ctrl->chan[chan_id];
|
|
sent_chan_frame_t *sent_chan_frame =
|
|
&ctrl->chan[chan_id].frame_info;
|
|
sdrv_sent_chan->chan_id = chan_id;
|
|
sdrv_sent_chan->tickfreq = cfg->chan_cfg[i].tickfreq;
|
|
sdrv_sent_chan->fifowml = cfg->chan_cfg[i].fifowml;
|
|
sdrv_sent_chan->lowpulse_width = cfg->chan_cfg[i].lowpulse_width;
|
|
sdrv_sent_chan->pause_pulse = cfg->chan_cfg[i].pause_pulse;
|
|
sent_chan_frame->frame_format = cfg->chan_cfg[i].fast_chan;
|
|
/* Set channel data information */
|
|
if (sent_chan_frame->frame_format == SENT_STANDARD_FORMAT) {
|
|
sent_chan_frame->frame_dl = cfg->chan_cfg[i].data_bitnum;
|
|
} else if (sent_chan_frame->frame_format ==
|
|
SENT_SINGLE_SECURE_FORMAT) {
|
|
sent_chan_frame->frame_dl = SENT_SECURE_SENSOR_DATA_NIBBLE;
|
|
} else if (sent_chan_frame->frame_format ==
|
|
SENT_HIGH_SPEED_FORMAT) {
|
|
/* High speed format has 4 data nibbles, one data nibble has 3
|
|
* bit. */
|
|
sent_chan_frame->frame_dl = SENT_HIGH_SPEED_DATA_NIBBLE;
|
|
}
|
|
/* Calculate the expect scaler value */
|
|
if (0U != sdrv_sent_chan->tickfreq) {
|
|
sdrv_sent_chan->expect_scaler =
|
|
(ctrl->clk_freq / (ctrl->clk_div + 1)) /
|
|
(sdrv_sent_chan->tickfreq);
|
|
}
|
|
/* Initialize sent channel. */
|
|
sdrv_sent_channel_init(ctrl, chan_id);
|
|
sdrv_sent_chan->chan_sta = CHAN_STATUS_INITED;
|
|
}
|
|
}
|
|
|
|
/* Enable sent and attach irq handler */
|
|
if (ctrl->irq > 0U) {
|
|
irq_attach(ctrl->irq, sdrv_sent_irq_handle, ctrl);
|
|
irq_enable(ctrl->irq);
|
|
}
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Sdrv sent controller deinitialization.
|
|
*
|
|
* This fuction deinitializes sent module.
|
|
*
|
|
* @param [in] ctrl Sdrv sent controller.
|
|
* @return The result of deinitializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null pointer.
|
|
* - SDRV_STATUS_OK : Sent is deinitialized success.
|
|
*/
|
|
status_t sdrv_sent_deinit(sdrv_sent_t *ctrl)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if (NULL == ctrl) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
/* Deinitialize sent module. */
|
|
if (SENT_STATUS_INITED == ctrl->sent_sta) {
|
|
ctrl->sent_sta = SENT_STATUS_UNINIT;
|
|
/* Disable sent irq handler */
|
|
if (ctrl->irq > 0U) {
|
|
irq_disable(ctrl->irq);
|
|
irq_detach(ctrl->irq);
|
|
}
|
|
sdrv_sent_module_deinit(ctrl);
|
|
/* Deinitialize the sent channels. */
|
|
for (sdrv_sent_chanid_e chan_id = SDRV_SENT_HW_CPT_A;
|
|
chan_id < ctrl->chan_num; ++chan_id) {
|
|
if (CHAN_STATUS_UNINIT != ctrl->chan[chan_id].chan_sta) {
|
|
ctrl->chan[chan_id].chan_sta = CHAN_STATUS_UNINIT;
|
|
/* restore predivider */
|
|
ctrl->chan[chan_id].expect_scaler = 0U;
|
|
ctrl->chan[chan_id].actual_scaler = 0U;
|
|
ctrl->chan[chan_id].frame_info.frame_dl = 0U;
|
|
sdrv_sent_channel_deinit(ctrl, chan_id);
|
|
}
|
|
}
|
|
}
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Sent set callback function
|
|
*
|
|
* @param[in] ctrl Sdrv sent controller.
|
|
* @param[in] sent_chan_id Sent channel id
|
|
* @param[in] callback Callback function
|
|
* @param[in] userdata Callback user param
|
|
* @return The result of initializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null pointer.
|
|
* - SDRV_STATUS_OK : Set callback function success.
|
|
*/
|
|
status_t sdrv_sent_set_callback(sdrv_sent_t *ctrl,
|
|
sdrv_sent_chanid_e sent_chan_id,
|
|
sdrv_sent_recv_cb_t callback, void *userdata)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
ctrl->chan[sent_chan_id].frameover_cb = callback;
|
|
ctrl->chan[sent_chan_id].userdata = userdata;
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Sent starts to receive frames.
|
|
*
|
|
* Sent channel will receive frames after calling this function.
|
|
* User could stop the sent channel by calling sdrv_sent_recv_stop().
|
|
*
|
|
* @param[in] ctrl Sent controller
|
|
* @param[in] sent_chan_id Sent channel id
|
|
* @return The result of initializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null pointer.
|
|
* - SDRV_STATUS_FAIL : Sent module or channel is uninitialized.
|
|
* - SDRV_STATUS_OK : Start sent channel success.
|
|
*/
|
|
status_t sdrv_sent_recv_start(sdrv_sent_t *ctrl,
|
|
sdrv_sent_chanid_e sent_chan_id)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
sdrv_sent_chan_t *sent_chan = &ctrl->chan[sent_chan_id];
|
|
|
|
if ((SENT_STATUS_UNINIT == ctrl->sent_sta) ||
|
|
(CHAN_STATUS_UNINIT == sent_chan->chan_sta)) {
|
|
return SDRV_STATUS_FAIL;
|
|
}
|
|
|
|
/* Stop sent channel if the channel is running. */
|
|
if (CHAN_STATUS_RUNNING == sent_chan->chan_sta) {
|
|
sdrv_sent_recv_stop(ctrl, sent_chan_id);
|
|
}
|
|
|
|
/* Initialize channel and frame status */
|
|
sent_chan->chan_sta = CHAN_STATUS_RUNNING;
|
|
sent_chan->frame_info.cur_state = SENT_IDLE;
|
|
sent_chan->frame_info.frame_err = SENT_OK;
|
|
|
|
/* Clear fifo. */
|
|
sdrv_etimer_lld_clear_fifo(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id);
|
|
/* Turn on dma request interrupt */
|
|
sdrv_etimer_lld_int_en(ctrl->base,
|
|
ETMR_BM_INT_STA_EN_CHN_DMA_REQ(sent_chan_id), true);
|
|
/* Enable capture module */
|
|
sdrv_etimer_lld_cpt_en(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
true);
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Sent stop recv frame
|
|
*
|
|
* Sent channel will receive frames after calling sdrv_sent_recv_start().
|
|
* User could stop the sent channel by calling this function.
|
|
*
|
|
* @param[in] ctrl Sent controller
|
|
* @param[in] sent_chan_id Sent channel id
|
|
* @return The result of initializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null pointer.
|
|
* - SDRV_STATUS_FAIL : Sent module or channel is uninitialized.
|
|
* - SDRV_STATUS_OK : Stop sent channel success.
|
|
*/
|
|
status_t sdrv_sent_recv_stop(sdrv_sent_t *ctrl, sdrv_sent_chanid_e sent_chan_id)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
sdrv_sent_chan_t *sent_chan = &ctrl->chan[sent_chan_id];
|
|
|
|
if ((SENT_STATUS_UNINIT == ctrl->sent_sta) ||
|
|
(CHAN_STATUS_UNINIT == sent_chan->chan_sta)) {
|
|
return SDRV_STATUS_FAIL;
|
|
}
|
|
|
|
if (CHAN_STATUS_RUNNING == sent_chan->chan_sta) {
|
|
/* Turn off dma request interrupt */
|
|
sdrv_etimer_lld_int_en(
|
|
ctrl->base, ETMR_BM_INT_STA_EN_CHN_DMA_REQ(sent_chan_id), false);
|
|
/* Disable capture module */
|
|
sdrv_etimer_lld_cpt_en(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
false);
|
|
sent_chan->chan_sta = CHAN_STATUS_STOPPED;
|
|
sent_chan->frame_info.cur_state = SENT_IDLE;
|
|
sent_chan->frame_info.frame_err = SENT_OK;
|
|
}
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Parse sent frame
|
|
*
|
|
* This function is used in the following two situations:
|
|
* 1.Enter sent interrupt,
|
|
* 2.The user actively calls function to parse the remaining data in fifo after
|
|
* stopping channal.
|
|
*
|
|
* @param[in] ctrl Sent controller
|
|
* @param[in] sent_chan_id Sent channel id
|
|
* @return The result of initializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null pointer.
|
|
* - SDRV_STATUS_OK : Parse sent frame success.
|
|
*/
|
|
status_t sdrv_sent_parse_msg(sdrv_sent_t *ctrl, sdrv_sent_chanid_e sent_chan_id)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
sdrv_sent_chan_t *sent_chan = &ctrl->chan[sent_chan_id];
|
|
sent_chan_frame_t *frame_info = &sent_chan->frame_info;
|
|
|
|
/* If occurs fifo error, clear fifo. */
|
|
if ((0x01U << ((sent_chan_id * 8U) + 7U)) &
|
|
sdrv_etimer_lld_get_fifo_sta(ctrl->base)) {
|
|
/* Clear fifo. */
|
|
sdrv_etimer_lld_clear_fifo(ctrl->base,
|
|
(sdrv_etimer_chn_id_e)sent_chan_id);
|
|
/* Updata frame status. */
|
|
frame_info->rx_index = 0U;
|
|
frame_info->frame_err = SENT_OK;
|
|
frame_info->cur_state = SENT_IDLE;
|
|
} else {
|
|
/* Get the length of data in dma fifo. */
|
|
uint32_t fifo_datanum = ETMR_GFV_FIFO_STA_FIFO_ENTRIES(
|
|
sdrv_etimer_lld_get_fifo_sta(ctrl->base), sent_chan_id);
|
|
/* Parse all data in dam fifo. */
|
|
for (uint32_t i = 0U; i < fifo_datanum; ++i) {
|
|
/* Get the data from fifo. */
|
|
uint32_t fifo_data = sdrv_etimer_lld_get_fifo_val(
|
|
ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id);
|
|
/* Parse data according to the current frame state. */
|
|
switch (frame_info->cur_state) {
|
|
case SENT_IDLE: {
|
|
if (0U != sent_chan->expect_scaler) {
|
|
/* Verificate the frequency of tick. */
|
|
uint32_t scaler10 = fifo_data * 10 / 56U;
|
|
uint32_t err_range = scaler10 / (sent_chan->expect_scaler);
|
|
if ((err_range >= 8U) && (err_range <= 12U)) {
|
|
sent_chan->actual_scaler =
|
|
(scaler10 % 10U) < 5 ? scaler10 / 10U : scaler10 / 10U + 1U;
|
|
frame_info->frame_err = SENT_OK;
|
|
frame_info->cur_state = SENT_SYNC;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SENT_SYNC: {
|
|
/* Parse data from fifo. */
|
|
uint32_t status_tick =
|
|
sdrv_tick_parse(fifo_data, sent_chan->actual_scaler);
|
|
/* Verificate tick count. */
|
|
if ((status_tick < 12U) || (status_tick > 27U)) {
|
|
frame_info->frame_err |= SENT_STATUS_ERR;
|
|
}
|
|
/* Update status value */
|
|
frame_info->frame_sta = (status_tick - 12U);
|
|
/* Updata frame status. */
|
|
frame_info->rx_index = 0U;
|
|
frame_info->cur_state = SENT_DATA;
|
|
break;
|
|
}
|
|
case SENT_DATA: {
|
|
/* Parse data from fifo. */
|
|
uint32_t data_tick =
|
|
sdrv_tick_parse(fifo_data, sent_chan->actual_scaler);
|
|
/* Verificate tick count. */
|
|
if ((data_tick < 12U) || (data_tick > 27U)) {
|
|
frame_info->frame_err |= SENT_DATA_ERR;
|
|
}
|
|
|
|
/* Data Value */
|
|
frame_info->rxframe[frame_info->rx_index % 6U] =
|
|
(data_tick - 12U);
|
|
++frame_info->rx_index;
|
|
if (frame_info->rx_index == sent_chan->frame_info.frame_dl) {
|
|
frame_info->rx_index = 0U;
|
|
frame_info->cur_state = SENT_CRC;
|
|
}
|
|
break;
|
|
}
|
|
case SENT_CRC: {
|
|
/* Parse data from fifo. */
|
|
uint32_t crc_tick =
|
|
sdrv_tick_parse(fifo_data, sent_chan->actual_scaler);
|
|
/* Verificate tick count. */
|
|
if ((crc_tick < 12U) || (crc_tick > 27U)) {
|
|
frame_info->frame_err |= SENT_CRC_ERR;
|
|
}
|
|
/* Check CRC value. */
|
|
uint8_t crc_calc = crc4_calculate(
|
|
5U, (unsigned char const *)frame_info->rxframe,
|
|
frame_info->frame_dl);
|
|
if (crc_calc != (crc_tick - 12U)) {
|
|
frame_info->frame_err |= SENT_CRC_ERR;
|
|
}
|
|
/* Update frame crc value */
|
|
frame_info->frame_crc = crc_tick - 12U;
|
|
memcpy(&g_frame_info[sent_chan_id], frame_info,
|
|
sizeof(sent_chan_frame_t));
|
|
g_frame_info[sent_chan_id].frame_valid = true;
|
|
/* Frame over if no pause pulse. */
|
|
if (sent_chan->pause_pulse == true) {
|
|
frame_info->cur_state = SENT_PAUSE;
|
|
} else {
|
|
/* Call callback function and update frame's current state
|
|
* to IDLE if frame over. */
|
|
frame_info->cur_state = SENT_IDLE;
|
|
if (sent_chan->frameover_cb) {
|
|
sent_chan->frameover_cb(ctrl, sent_chan_id,
|
|
sent_chan->userdata);
|
|
}
|
|
frame_info->frame_err = SENT_OK;
|
|
}
|
|
break;
|
|
}
|
|
case SENT_PAUSE: {
|
|
/* Call callback function and update frame's current state to
|
|
* IDLE if frame over. */
|
|
frame_info->cur_state = SENT_IDLE;
|
|
if (sent_chan->frameover_cb) {
|
|
sent_chan->frameover_cb(ctrl, sent_chan_id,
|
|
sent_chan->userdata);
|
|
}
|
|
frame_info->frame_err = SENT_OK;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Get sent frame info
|
|
*
|
|
* @param[in] ctrl Sent controller
|
|
* @param[in] sent_chan_id Sent channel id
|
|
* @param[out] frame_err Frame error code
|
|
* @param[out] frame Frame information
|
|
* @return The result of initializing sent.
|
|
* - SDRV_STATUS_INVALID_PARAM : The input parameter contains a null pointer.
|
|
* - SDRV_STATUS_FAIL : The state of channel is error or the frame is invalid.
|
|
* - SDRV_STATUS_OK : Get sent frame success.
|
|
*/
|
|
status_t sdrv_sent_get_frame(sdrv_sent_t *ctrl, sdrv_sent_chanid_e sent_chan_id,
|
|
uint32_t *frame_err, sent_chan_frame_t *frame)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (NULL == frame_err) || (NULL == frame) ||
|
|
(sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return SDRV_STATUS_INVALID_PARAM;
|
|
}
|
|
|
|
sdrv_sent_chan_t *sent_chan = &ctrl->chan[sent_chan_id];
|
|
|
|
/* Check the channel status */
|
|
if (sent_chan->chan_sta != CHAN_STATUS_RUNNING) {
|
|
return SDRV_STATUS_FAIL;
|
|
}
|
|
|
|
uint32_t ulCpsr = arch_irq_save();
|
|
/* Get frame data from sent global buffer. */
|
|
if (g_frame_info[sent_chan_id].frame_valid) {
|
|
memcpy(frame, &g_frame_info[sent_chan_id], sizeof(sent_chan_frame_t));
|
|
*frame_err = g_frame_info[sent_chan_id].frame_err;
|
|
g_frame_info[sent_chan_id].frame_valid = false;
|
|
arch_irq_restore(ulCpsr);
|
|
} else {
|
|
arch_irq_restore(ulCpsr);
|
|
return SDRV_STATUS_FAIL;
|
|
}
|
|
|
|
return SDRV_STATUS_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Sdrv sent interrupt handler.
|
|
*
|
|
* @param [in] irq The irq number of uartx
|
|
* @param [in] ctrl Sdrv sent controller
|
|
*/
|
|
int sdrv_sent_irq_handle(uint32_t irq, void *ctrl)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if (NULL == ctrl) {
|
|
return -1;
|
|
}
|
|
|
|
sdrv_sent_t *sdrv_sent = (sdrv_sent_t *)ctrl;
|
|
/* Get sent channel interrupt status. */
|
|
uint32_t sent_sta = sdrv_etimer_lld_get_int_status(sdrv_sent->base);
|
|
/* Handle all channels interrupt. */
|
|
for (sdrv_sent_chanid_e id = SDRV_SENT_HW_CPT_A; id < SDRV_SENT_CHAN_NUM;
|
|
++id) {
|
|
if (sent_sta & ETMR_BM_INT_STA_CHN_DMA_REQ(id)) {
|
|
/* Parse the data in dma fifo. */
|
|
sdrv_sent_parse_msg(sdrv_sent, id);
|
|
/* Clear the channel interrupt status. */
|
|
sdrv_etimer_lld_clear_int_status(sdrv_sent->base,
|
|
ETMR_BM_INT_STA_CHN_DMA_REQ(id));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**************************Static Functions Start******************************/
|
|
/**
|
|
* brief Sdrv sent channel id map to etimer channel id.
|
|
*
|
|
* param [in] sent_chan_id Sent channel id
|
|
* param [out] etimer_cnt_id Sdrv etimer channel id
|
|
*/
|
|
static void sdrv_chanid_map(sdrv_sent_chanid_e sent_chan_id,
|
|
sdrv_etimer_cnt_id_e *etimer_cnt_id)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((sent_chan_id > SDRV_SENT_HW_CPT_D) || (NULL == etimer_cnt_id)) {
|
|
return;
|
|
}
|
|
/* Exchanging etimer channel number to sent channel number. */
|
|
*etimer_cnt_id = (sdrv_etimer_cnt_id_e)(sent_chan_id + 2U);
|
|
}
|
|
|
|
/**
|
|
* brief Sdrv sent module initialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
*/
|
|
static void sdrv_sent_module_init(sdrv_sent_t *ctrl)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if (NULL == ctrl) {
|
|
return;
|
|
}
|
|
|
|
/* Disable clock monitor. */
|
|
sdrv_etimer_lld_clk_mon_en(ctrl->base, false);
|
|
/* Config clock. */
|
|
clk_set_t clk_set = {0U};
|
|
clk_set.src_clk_sel = (sdrv_etimer_clk_src_e)ctrl->clk_sel;
|
|
clk_set.div_num = (uint32_t)ctrl->clk_div;
|
|
sdrv_etimer_lld_clk_cfg(ctrl->base, &clk_set);
|
|
/* Enable clock monitor. */
|
|
sdrv_etimer_lld_clk_mon_en(ctrl->base, true);
|
|
}
|
|
|
|
/**
|
|
* brief Sdrv sent module deinitialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
*/
|
|
static void sdrv_sent_module_deinit(sdrv_sent_t *ctrl)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if (NULL == ctrl) {
|
|
return;
|
|
}
|
|
|
|
/* Disable clock monitor. */
|
|
sdrv_etimer_lld_clk_mon_en(ctrl->base, false);
|
|
/* Config clock. */
|
|
clk_set_t clk_set = {0U};
|
|
sdrv_etimer_lld_clk_cfg(ctrl->base, &clk_set);
|
|
/* Enable clock monitor. */
|
|
sdrv_etimer_lld_clk_mon_en(ctrl->base, true);
|
|
}
|
|
|
|
/**
|
|
* brief Sdrv sent channel initialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
* param [in] sent_chan_id Sent channel id
|
|
*/
|
|
static void sdrv_sent_channel_init(sdrv_sent_t *ctrl,
|
|
sdrv_sent_chanid_e sent_chan_id)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return;
|
|
}
|
|
|
|
sdrv_sent_chan_t *sdrv_sent_chan = &ctrl->chan[sent_chan_id];
|
|
sdrv_etimer_cnt_id_e etimer_cnt_id;
|
|
sdrv_chanid_map(sent_chan_id, &etimer_cnt_id);
|
|
|
|
/* Set timer counter ovf value 0xFFFFFFFFU */
|
|
sdrv_etimer_lld_cnt_ovf(ctrl->base, etimer_cnt_id, 0xFFFFFFFFU);
|
|
|
|
/* Cnt will start when the first cpt event happen */
|
|
local_cnt_config_t sdrv_lcnt_cfg = {0U};
|
|
sdrv_lcnt_cfg.start_by_first_cpt = true;
|
|
sdrv_etimer_lld_local_cnt_cfg(ctrl->base, etimer_cnt_id, &sdrv_lcnt_cfg);
|
|
|
|
/* Reset the counter when the cpt0 event happen */
|
|
sdrv_etimer_lld_lcnt_cpt_clr_en(ctrl->base, etimer_cnt_id,
|
|
SDRV_ETIMR_LCNT_CPT_0_CLR, true);
|
|
|
|
/* Enable timer counter */
|
|
sdrv_etimer_lld_cnt_en(ctrl->base, etimer_cnt_id, true);
|
|
|
|
/* Set the triggered edge as falling edge, set the local timer as capture
|
|
* counter */
|
|
cpt_config_t sdrv_cpt_cfg;
|
|
memset(&sdrv_cpt_cfg, 0, sizeof(cpt_config_t));
|
|
sdrv_cpt_cfg.cpt0_trig_mode = SDRV_ETIMR_CPT_FALL_EDGE;
|
|
sdrv_cpt_cfg.cnt_sel = SDRV_ETIMR_CPT_LCNT;
|
|
sdrv_etimer_lld_cpt_cfg(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
&sdrv_cpt_cfg);
|
|
sdrv_etimer_lld_cpt_config_set(ctrl->base,
|
|
(sdrv_etimer_chn_id_e)sent_chan_id);
|
|
|
|
/* Set water mark level value */
|
|
sdrv_etimer_lld_dma_wml(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
sdrv_sent_chan->fifowml);
|
|
|
|
/* Set dma block as capture */
|
|
chn_etimer_dma_ctrl_t sdrv_dmactrl_cfg = {0U};
|
|
sdrv_dmactrl_cfg.block_sel = SDRV_ETIMR_CPT_BLOCK;
|
|
sdrv_dmactrl_cfg.chn_en = 1U;
|
|
sdrv_etimer_lld_dma_chn_cfg(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
&sdrv_dmactrl_cfg);
|
|
|
|
/* Enable capture filter. */
|
|
if (sdrv_sent_chan->filter_en) {
|
|
flt_config_t filter_cfg;
|
|
filter_cfg.flt_edge_sel = SDRV_ETIMR_FLT_NEGEEDGE;
|
|
filter_cfg.neg_band_wid = 0U;
|
|
filter_cfg.neg_band_wid = sdrv_sent_chan->filter_bandwidth;
|
|
filter_cfg.sample_intval = sdrv_sent_chan->sample_interval;
|
|
sdrv_etimer_lld_cpt_flt_cfg(
|
|
ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id, &filter_cfg);
|
|
sdrv_etimer_lld_cpt_flt_en(ctrl->base,
|
|
(sdrv_etimer_chn_id_e)sent_chan_id, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* brief Sdrv sent channel deinitialize.
|
|
*
|
|
* param [in] ctrl Sdrv sent controller entity
|
|
* param [in] sent_chan_id Sent channel id
|
|
*/
|
|
static void sdrv_sent_channel_deinit(sdrv_sent_t *ctrl,
|
|
sdrv_sent_chanid_e sent_chan_id)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if ((NULL == ctrl) || (sent_chan_id > SDRV_SENT_HW_CPT_D)) {
|
|
return;
|
|
}
|
|
|
|
sdrv_etimer_cnt_id_e etimer_cnt_id;
|
|
sdrv_chanid_map(sent_chan_id, &etimer_cnt_id);
|
|
/* Turn off dma req interrupt */
|
|
sdrv_etimer_lld_int_en(ctrl->base,
|
|
ETMR_BM_INT_STA_EN_CHN_DMA_REQ(sent_chan_id), false);
|
|
/* Disable cpt module */
|
|
sdrv_etimer_lld_cpt_en(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
false);
|
|
|
|
/* Restore timer counter overflow value 0 */
|
|
sdrv_etimer_lld_cnt_ovf(ctrl->base, etimer_cnt_id, 0U);
|
|
|
|
/* Overflow will be updated to shadow register */
|
|
sdrv_etimer_lld_cnt_upd(ctrl->base, etimer_cnt_id, false, true);
|
|
|
|
/* Restore the cnt cfg */
|
|
local_cnt_config_t sdrv_lcnt_cfg = {0U};
|
|
sdrv_lcnt_cfg.start_by_first_cpt = false;
|
|
sdrv_etimer_lld_local_cnt_cfg(ctrl->base, etimer_cnt_id, &sdrv_lcnt_cfg);
|
|
sdrv_etimer_lld_lcnt_cpt_clr_en(ctrl->base, etimer_cnt_id,
|
|
SDRV_ETIMR_LCNT_CPT_0_CLR, false);
|
|
|
|
/* Disable timer counter */
|
|
sdrv_etimer_lld_cnt_en(ctrl->base, etimer_cnt_id, false);
|
|
|
|
/* Restore the triggered edge, restore the timer as capture counter */
|
|
cpt_config_t sdrv_cpt_cfg;
|
|
memset(&sdrv_cpt_cfg, 0, sizeof(cpt_config_t));
|
|
sdrv_cpt_cfg.cpt0_trig_mode = SDRV_ETIMR_CPT_RISE_EDGE;
|
|
sdrv_cpt_cfg.cnt_sel = SDRV_ETIMR_CPT_CNTG0;
|
|
sdrv_etimer_lld_cpt_cfg(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
&sdrv_cpt_cfg);
|
|
sdrv_etimer_lld_cpt_config_set(ctrl->base,
|
|
(sdrv_etimer_chn_id_e)sent_chan_id);
|
|
|
|
/* Restore water mark level value */
|
|
sdrv_etimer_lld_dma_wml(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id, 0U);
|
|
|
|
/* Set dma block as default block */
|
|
chn_etimer_dma_ctrl_t sdrv_dmactrl_cfg = {0U};
|
|
sdrv_dmactrl_cfg.block_sel = SDRV_ETIMR_CMP_BLOCK;
|
|
sdrv_dmactrl_cfg.chn_en = 0U;
|
|
sdrv_etimer_lld_dma_chn_cfg(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
&sdrv_dmactrl_cfg);
|
|
|
|
/* Disable capture filter. */
|
|
sdrv_etimer_lld_cpt_flt_en(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id,
|
|
false);
|
|
|
|
/* Reset the channel count. */
|
|
sdrv_etimer_lld_sw_rst(ctrl->base, 1U << sent_chan_id);
|
|
|
|
/* Clear fifo. */
|
|
sdrv_etimer_lld_clear_fifo(ctrl->base, (sdrv_etimer_chn_id_e)sent_chan_id);
|
|
}
|
|
|
|
/**
|
|
* brief Parse data to tick.
|
|
*
|
|
* param [in] data data in dma fifo.
|
|
* param [in] actual_scaler sent channel actual scaler.
|
|
* return The count of tick.
|
|
*/
|
|
static uint32_t sdrv_tick_parse(uint32_t data, uint32_t actual_scaler)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if (0U == actual_scaler) {
|
|
return 0U;
|
|
}
|
|
/* Round off the number of tick. */
|
|
uint32_t ticktimes10 = (data * 10U) / actual_scaler;
|
|
return ((ticktimes10 % 10) < 5U) ? (ticktimes10 / 10U)
|
|
: (ticktimes10 / 10U + 1U);
|
|
}
|
|
|
|
/**
|
|
* brief Check the configurations of sent.
|
|
*
|
|
* param [in] cfg Sdrv sent configurations.
|
|
* return The configurations are valid or not.
|
|
* - true : The configurations of sent are valid.
|
|
* - false : The configurations of sent are unvalid.
|
|
*/
|
|
static bool sdrv_sent_config_check(sdrv_sent_config_t *cfg)
|
|
{
|
|
/* Parameters are valid or not. */
|
|
if (NULL == cfg) {
|
|
return false;
|
|
}
|
|
|
|
/* Check sent module configurations. */
|
|
if ((0U == cfg->base) || (0U == cfg->irq) || (0U == cfg->clk_freq) ||
|
|
(cfg->clk_div > 65534U) || (0U == cfg->chan_cfg_num)) {
|
|
return false;
|
|
}
|
|
/* Check sent channel configurations. */
|
|
for (uint8_t i = 0; i < cfg->chan_cfg_num; ++i) {
|
|
if ((0U == cfg->chan_cfg[i].tickfreq) ||
|
|
(cfg->chan_cfg[i].chan_id >= SDRV_SENT_CHAN_NUM) ||
|
|
(cfg->chan_cfg[i].data_bitnum > SENT_DATA_WIDTH_24_BIT) ||
|
|
(0U == cfg->chan_cfg[i].fifowml) ||
|
|
(cfg->chan_cfg[i].fifowml > 0X0FU) ||
|
|
(cfg->chan_cfg[i].lowpulse_width < 5U) ||
|
|
(cfg->chan_cfg[i].lowpulse_width > 12U) ||
|
|
((cfg->chan_cfg[i].filter_en) &&
|
|
((cfg->chan_cfg[i].filter_bandwidth < 2U) ||
|
|
(cfg->chan_cfg[i].filter_bandwidth > 17U)))) {
|
|
return false;
|
|
}
|
|
|
|
/* Check sent channel expect_scaler. */
|
|
uint32_t expect_scaler =
|
|
(cfg->clk_freq / (cfg->clk_div + 1U)) / (cfg->chan_cfg[i].tickfreq);
|
|
if (0U == expect_scaler) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
/**************************Static Functions End********************************/
|