346 lines
11 KiB
C
346 lines
11 KiB
C
|
#include "plat_addr_map.h"
|
||
|
#include "cmsis_nvic.h"
|
||
|
#include "hal_dma.h"
|
||
|
#include "hal_sensor_eng.h"
|
||
|
#include "hal_timer.h"
|
||
|
#include "hal_trace.h"
|
||
|
#include CHIP_SPECIFIC_HDR(reg_sensor_eng)
|
||
|
#include "reg_timer.h"
|
||
|
#include "string.h"
|
||
|
#ifdef RTOS
|
||
|
#include "cmsis_os.h"
|
||
|
#endif
|
||
|
|
||
|
#define MAX_RX_FRAME_NUM (5)
|
||
|
|
||
|
static struct SENSOR_ENG_T * const sensor_eng[] = {
|
||
|
(struct SENSOR_ENG_T *)SENSOR_ENG_BASE,
|
||
|
};
|
||
|
|
||
|
static struct DUAL_TIMER_T * const sensor_eng_timer = (struct DUAL_TIMER_T *)MCU_TIMER2_BASE;
|
||
|
|
||
|
static struct HAL_DMA_DESC_T tx_dma_desc[1];
|
||
|
static struct HAL_DMA_DESC_T rx_dma_desc[MAX_RX_FRAME_NUM];
|
||
|
|
||
|
static HAL_SENSOR_ENG_HANDLER_T sensor_eng_handler;
|
||
|
|
||
|
static uint8_t dma_rx_chan;
|
||
|
|
||
|
static uint8_t *dma_rx_buf;
|
||
|
static uint32_t dma_rx_len;
|
||
|
static uint32_t prev_rx_pos;
|
||
|
|
||
|
void hal_sensor_process_rx_buffer(void)
|
||
|
{
|
||
|
if (dma_rx_len == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uint8_t *dma_buf_active = (uint8_t *)hal_dma_get_cur_dst_addr(dma_rx_chan);
|
||
|
uint32_t result_len = 0;
|
||
|
uint8_t *curr_pos;
|
||
|
|
||
|
curr_pos = dma_rx_buf + prev_rx_pos;
|
||
|
|
||
|
//TRACE(2,"dma_buf_active:%08x curr_pos:%08x", dma_buf_active, curr_pos);
|
||
|
|
||
|
if (dma_buf_active < curr_pos) {
|
||
|
result_len = dma_rx_buf + dma_rx_len - curr_pos;
|
||
|
//TRACE(2,"1:result_len:%08x, curr_pos:%08x", result_len, curr_pos);
|
||
|
//DUMP8("%02x ", curr_pos, result_len);
|
||
|
if (sensor_eng_handler){
|
||
|
sensor_eng_handler(HAL_SENSOR_ENGINE_ID_0, HAL_SENSOR_ENGINE_DEVICE_I2C0, curr_pos, result_len);
|
||
|
}
|
||
|
curr_pos = dma_rx_buf;
|
||
|
}
|
||
|
|
||
|
if (curr_pos < dma_buf_active) {
|
||
|
result_len = dma_buf_active - curr_pos;
|
||
|
//TRACE(2,"2:result_len:%08x, curr_pos:%08x", result_len, curr_pos);
|
||
|
//DUMP8("%02x ", curr_pos, result_len);
|
||
|
if (sensor_eng_handler){
|
||
|
sensor_eng_handler(HAL_SENSOR_ENGINE_ID_0, HAL_SENSOR_ENGINE_DEVICE_I2C0, curr_pos, result_len);
|
||
|
}
|
||
|
curr_pos = dma_buf_active;
|
||
|
}
|
||
|
|
||
|
prev_rx_pos = curr_pos - dma_rx_buf;
|
||
|
}
|
||
|
|
||
|
static void hal_sensor_eng_irq_handler(void)
|
||
|
{
|
||
|
//TRACE(2,"%s: irq=0x%08x", __func__, sensor_eng[0]->SENSOR_INTR_STS);
|
||
|
|
||
|
sensor_eng[0]->SENSOR_INTR_CLR = SENSOR_INTR_CLEAR;
|
||
|
|
||
|
hal_sensor_process_rx_buffer();
|
||
|
}
|
||
|
|
||
|
static void hal_sensor_eng_irq_enable(void)
|
||
|
{
|
||
|
NVIC_SetVector(SENSOR_WKUP_IRQn, (uint32_t)hal_sensor_eng_irq_handler);
|
||
|
NVIC_SetPriority(SENSOR_WKUP_IRQn, IRQ_PRIORITY_HIGH);
|
||
|
NVIC_ClearPendingIRQ(SENSOR_WKUP_IRQn);
|
||
|
NVIC_EnableIRQ(SENSOR_WKUP_IRQn);
|
||
|
}
|
||
|
|
||
|
static void hal_sensor_eng_irq_disable(void)
|
||
|
{
|
||
|
NVIC_DisableIRQ(SENSOR_WKUP_IRQn);
|
||
|
}
|
||
|
|
||
|
static void hal_sensor_eng_timer_stop(void)
|
||
|
{
|
||
|
sensor_eng_timer->timer[0].Control = 0;
|
||
|
sensor_eng_timer->timer[0].IntClr = 1;
|
||
|
}
|
||
|
|
||
|
static void hal_sensor_eng_timer_open(uint32_t ticks)
|
||
|
{
|
||
|
if (ticks > 1) {
|
||
|
ticks -= 1;
|
||
|
} else {
|
||
|
ticks = 1;
|
||
|
}
|
||
|
sensor_eng_timer->timer[0].Load = ticks;
|
||
|
sensor_eng_timer->timer[0].Control = TIMER_CTRL_MODE_PERIODIC | TIMER_CTRL_INTEN | TIMER_CTRL_PRESCALE_DIV_1 | TIMER_CTRL_SIZE_32_BIT;
|
||
|
}
|
||
|
|
||
|
static void hal_sensor_eng_timer_start(void)
|
||
|
{
|
||
|
sensor_eng_timer->timer[0].Control |= TIMER_CTRL_EN;
|
||
|
}
|
||
|
|
||
|
int hal_sensor_engine_open(const struct HAL_SENSOR_ENGINE_CFG_T *cfg)
|
||
|
{
|
||
|
struct HAL_DMA_CH_CFG_T rx_dma_cfg;
|
||
|
enum HAL_DMA_RET_T dret;
|
||
|
uint32_t i;
|
||
|
uint32_t sx_sel;
|
||
|
|
||
|
ASSERT(cfg->id == HAL_SENSOR_ENGINE_ID_0, "Bad sensor engine id: %d", cfg->id);
|
||
|
ASSERT(cfg->device == HAL_SENSOR_ENGINE_DEVICE_I2C0, "Bad sensor engine device: %d", cfg->device);
|
||
|
ASSERT(cfg->rx_burst_cnt <= MAX_RX_FRAME_NUM, "Bad rx_burst_cnt: %d", cfg->rx_burst_cnt);
|
||
|
ASSERT(cfg->tx_dma_cfg, "Bad tx_dma_cfg");
|
||
|
|
||
|
sensor_eng_handler = cfg->handler;
|
||
|
dma_rx_chan = cfg->rx_dma_cfg->ch;
|
||
|
dma_rx_buf = (uint8_t *)cfg->rx_dma_cfg->dst;
|
||
|
dma_rx_len = cfg->rx_burst_len * cfg->rx_burst_cnt;
|
||
|
prev_rx_pos = 0;
|
||
|
|
||
|
dret = hal_dma_init_desc(&tx_dma_desc[0], cfg->tx_dma_cfg, &tx_dma_desc[0], 0);
|
||
|
ASSERT(dret == HAL_DMA_OK, "SensorEng: Failed to init tx desc 0");
|
||
|
|
||
|
dret = hal_gpdma_sg_start(&tx_dma_desc[0], cfg->tx_dma_cfg);
|
||
|
ASSERT(dret == HAL_DMA_OK, "SensorEng: Failed to start tx dma");
|
||
|
|
||
|
if (dma_rx_len) {
|
||
|
ASSERT(cfg->rx_dma_cfg, "Bad rx_dma_cfg");
|
||
|
|
||
|
rx_dma_cfg = *cfg->rx_dma_cfg;
|
||
|
for (i = 0; i < cfg->rx_burst_cnt; i++) {
|
||
|
rx_dma_cfg.dst = (uint32_t)(dma_rx_buf + cfg->rx_burst_len * i);
|
||
|
if (i + 1 == cfg->rx_burst_cnt) {
|
||
|
dret = hal_dma_init_desc(&rx_dma_desc[i], &rx_dma_cfg, &rx_dma_desc[0], 0);
|
||
|
} else {
|
||
|
dret = hal_dma_init_desc(&rx_dma_desc[i], &rx_dma_cfg, &rx_dma_desc[i + 1], 0);
|
||
|
}
|
||
|
ASSERT(dret == HAL_DMA_OK, "SensorEng: Failed to init rx desc %d", i);
|
||
|
}
|
||
|
hal_gpdma_sg_start(&rx_dma_desc[0], cfg->rx_dma_cfg);
|
||
|
ASSERT(dret == HAL_DMA_OK, "SensorEng: Failed to start rx dma");
|
||
|
}
|
||
|
|
||
|
hal_cmu_clock_enable(HAL_CMU_MOD_H_SENSOR_ENG);
|
||
|
hal_cmu_reset_clear(HAL_CMU_MOD_H_SENSOR_ENG);
|
||
|
hal_cmu_clock_enable(HAL_CMU_MOD_O_TIMER2);
|
||
|
hal_cmu_clock_enable(HAL_CMU_MOD_P_TIMER2);
|
||
|
hal_cmu_reset_clear(HAL_CMU_MOD_O_TIMER2);
|
||
|
hal_cmu_reset_clear(HAL_CMU_MOD_P_TIMER2);
|
||
|
|
||
|
sensor_eng[0]->SLV0_CONFIG_REG = SLV_I2C_SPI_SEL(cfg->device) | SLV_SLV_DEV_ID(cfg->device_address) | SLV_ENABLE;
|
||
|
if (dma_rx_len) {
|
||
|
//RX LLI = 1
|
||
|
sensor_eng[0]->GLOBAL_CFG1_REG = SET_BITFIELD(sensor_eng[0]->GLOBAL_CFG1_REG, NUM_OF_RX_LLI0, 1);
|
||
|
}
|
||
|
//TX LLI = 1
|
||
|
sensor_eng[0]->GLOBAL_CFG3_REG = SET_BITFIELD(sensor_eng[0]->GLOBAL_CFG3_REG, NUM_OF_TX_LLI0, 1);
|
||
|
if (cfg->trigger_type == HAL_SENSOR_ENGINE_TRIGGER_GPIO) {
|
||
|
sensor_eng[0]->SLV0_INTR_MASK = ~(1 << cfg->trigger_gpio);
|
||
|
}
|
||
|
|
||
|
if (cfg->data_to_vad) {
|
||
|
sx_sel = cfg->id;
|
||
|
} else {
|
||
|
sx_sel = GET_BITFIELD(sensor_eng[0]->GLOBAL_CFG0_REG, GBL_CODEC_SX_SEL);
|
||
|
}
|
||
|
sensor_eng[0]->GLOBAL_CFG0_REG = GBL_CODEC_SX_SEL(sx_sel) | GBL_SENSORHUB_EN |
|
||
|
(cfg->trigger_type == HAL_SENSOR_ENGINE_TRIGGER_GPIO ? GBL_TRIGGER_TYPE : 0);
|
||
|
|
||
|
if (cfg->trigger_type == HAL_SENSOR_ENGINE_TRIGGER_TIMER) {
|
||
|
hal_sensor_eng_timer_open(US_TO_TICKS(cfg->period_us));
|
||
|
hal_sensor_eng_timer_start();
|
||
|
}
|
||
|
|
||
|
hal_sensor_eng_irq_enable();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int hal_sensor_engine_close(enum HAL_SENSOR_ENGINE_ID_T id)
|
||
|
{
|
||
|
uint32_t cnt;
|
||
|
|
||
|
hal_sensor_eng_irq_disable();
|
||
|
|
||
|
hal_sensor_eng_timer_stop();
|
||
|
|
||
|
sensor_eng[0]->GLOBAL_CFG0_REG &= ~GBL_SENSORHUB_EN;
|
||
|
|
||
|
// Wait until sensor engine becomes idle
|
||
|
cnt = 0;
|
||
|
while ((sensor_eng[0]->SENSOR_STATUS & SENSOR_ENG_FSM_MASK) && cnt < 10) {
|
||
|
osDelay(1);
|
||
|
cnt++;
|
||
|
}
|
||
|
if (sensor_eng[0]->SENSOR_STATUS & SENSOR_ENG_FSM_MASK) {
|
||
|
ASSERT(false, "%s: Sensor engine cannot become idle: 0x%08X", __func__, sensor_eng[0]->SENSOR_STATUS);
|
||
|
}
|
||
|
|
||
|
sensor_eng[0]->SLV0_INTR_MASK = ~0UL;
|
||
|
|
||
|
dma_rx_len = 0;
|
||
|
|
||
|
hal_cmu_reset_set(HAL_CMU_MOD_P_TIMER2);
|
||
|
hal_cmu_reset_set(HAL_CMU_MOD_O_TIMER2);
|
||
|
hal_cmu_clock_disable(HAL_CMU_MOD_P_TIMER2);
|
||
|
hal_cmu_clock_disable(HAL_CMU_MOD_O_TIMER2);
|
||
|
hal_cmu_reset_set(HAL_CMU_MOD_H_SENSOR_ENG);
|
||
|
hal_cmu_clock_disable(HAL_CMU_MOD_H_SENSOR_ENG);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
#include "hal_i2c.h"
|
||
|
|
||
|
#define READ_BUF_BURST_CNT 5
|
||
|
#define TRIGGER_TIMER_US 500000
|
||
|
#define LOCK_INTR_CNT 3
|
||
|
#define TRIGGER_GPIO_PIN HAL_GPIO_PIN_P0_0
|
||
|
|
||
|
static void hal_sensor_eng_external_input_pin_irqhandler(enum HAL_GPIO_PIN_T pin)
|
||
|
{
|
||
|
bool gpio_lvl = 0;
|
||
|
gpio_lvl = hal_gpio_pin_get_val(pin);
|
||
|
TRACE(2,"hal_sensor_eng_external_irqhandler io=%d val=%d", pin, gpio_lvl);
|
||
|
}
|
||
|
|
||
|
static void sensor_timer_test_handler(enum HAL_I2C_ID_T id, const uint8_t *buf, uint32_t len)
|
||
|
{
|
||
|
TRACE(7,"%s: id=%d len=%u %02X-%02X-%02X-%02x", __FUNCTION__, id, len, buf[0], buf[1], buf[2], buf[3]);
|
||
|
}
|
||
|
|
||
|
static void sensor_gpio_test_handler(enum HAL_I2C_ID_T id, const uint8_t *buf, uint32_t len)
|
||
|
{
|
||
|
TRACE(7,"%s: id=%d len=%u %02X-%02X-%02X-%02x", __FUNCTION__, id, len, buf[0], buf[1], buf[2], buf[3]);
|
||
|
}
|
||
|
|
||
|
static int sensor_eng_test(enum HAL_SENSOR_ENGINE_TRIGGER_T trigger_type)
|
||
|
{
|
||
|
static uint8_t write_buf[3];
|
||
|
static uint8_t read_buf[READ_BUF_BURST_CNT][sizeof(write_buf) * 2];
|
||
|
|
||
|
int ret;
|
||
|
struct HAL_I2C_CONFIG_T cfg;
|
||
|
struct HAL_I2C_SENSOR_ENGINE_CONFIG_T se_cfg;
|
||
|
enum HAL_I2C_ID_T id;
|
||
|
uint32_t i;
|
||
|
|
||
|
id = HAL_I2C_ID_0;
|
||
|
|
||
|
for (i = 0; i < sizeof(write_buf); i++) {
|
||
|
write_buf[i] = i;
|
||
|
}
|
||
|
|
||
|
memset(&cfg, 0, sizeof(cfg));
|
||
|
cfg.mode = HAL_I2C_API_MODE_SENSOR_ENGINE;
|
||
|
cfg.as_master = 1;
|
||
|
cfg.use_dma = 1;
|
||
|
cfg.use_sync = 1;
|
||
|
cfg.speed = 100000;
|
||
|
ret = hal_i2c_open(id, &cfg);
|
||
|
if (ret) {
|
||
|
TRACE(2,"%s: i2c open failed %d", __func__, ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
memset(&se_cfg, 0, sizeof(se_cfg));
|
||
|
se_cfg.id = HAL_SENSOR_ENGINE_ID_0;
|
||
|
se_cfg.trigger_type = trigger_type;
|
||
|
if (trigger_type == HAL_SENSOR_ENGINE_TRIGGER_TIMER) {
|
||
|
se_cfg.period_us = TRIGGER_TIMER_US;
|
||
|
se_cfg.handler = sensor_timer_test_handler;
|
||
|
} else {
|
||
|
se_cfg.trigger_gpio = TRIGGER_GPIO_PIN;
|
||
|
se_cfg.handler = sensor_gpio_test_handler;
|
||
|
}
|
||
|
se_cfg.target_addr = 0x17;
|
||
|
se_cfg.write_buf = &write_buf[0];
|
||
|
se_cfg.write_txn_len = 1;
|
||
|
se_cfg.read_buf = &read_buf[0][0];
|
||
|
se_cfg.read_txn_len = 2;
|
||
|
se_cfg.txn_cnt = sizeof(write_buf);
|
||
|
se_cfg.read_burst_cnt = READ_BUF_BURST_CNT;
|
||
|
|
||
|
hal_i2c_sensor_engine_start(id, &se_cfg);
|
||
|
|
||
|
uint32_t lock = int_lock();
|
||
|
while (1) {
|
||
|
hal_sys_timer_delay(US_TO_TICKS(TRIGGER_TIMER_US) * LOCK_INTR_CNT);
|
||
|
TRACE_IMM(2,"%s: delay %u ms", __func__, (TRIGGER_TIMER_US / 1000 * LOCK_INTR_CNT));
|
||
|
hal_sensor_process_rx_buffer();
|
||
|
}
|
||
|
int_unlock(lock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int hal_sensor_eng_periodic_timer_test(void)
|
||
|
{
|
||
|
sensor_eng_test(HAL_SENSOR_ENGINE_TRIGGER_TIMER);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int hal_sensor_eng_external_input_test(void)
|
||
|
{
|
||
|
static const struct HAL_IOMUX_PIN_FUNCTION_MAP ext_pin[] = {
|
||
|
{TRIGGER_GPIO_PIN, HAL_IOMUX_FUNC_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE},
|
||
|
};
|
||
|
struct HAL_GPIO_IRQ_CFG_T gpiocfg;
|
||
|
|
||
|
sensor_eng_test(HAL_SENSOR_ENGINE_TRIGGER_GPIO);
|
||
|
|
||
|
hal_iomux_init((struct HAL_IOMUX_PIN_FUNCTION_MAP *)ext_pin, sizeof(ext_pin)/sizeof(struct HAL_IOMUX_PIN_FUNCTION_MAP));
|
||
|
hal_gpio_pin_set_dir(TRIGGER_GPIO_PIN, HAL_GPIO_DIR_IN, 1);
|
||
|
|
||
|
gpiocfg.irq_enable = true;
|
||
|
gpiocfg.irq_debounce = false;
|
||
|
gpiocfg.irq_polarity = HAL_GPIO_IRQ_POLARITY_HIGH_RISING;
|
||
|
gpiocfg.irq_handler = hal_sensor_eng_external_input_pin_irqhandler;
|
||
|
gpiocfg.irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE;
|
||
|
|
||
|
hal_gpio_setup_irq(TRIGGER_GPIO_PIN, &gpiocfg);
|
||
|
|
||
|
TRACE(5,"SLV0:%08x CFG1:0x%08x CFG3:0x%08x CFG0:0x%08x INTR_MASK:0x%08x",
|
||
|
sensor_eng[0]->SLV0_CONFIG_REG,
|
||
|
sensor_eng[0]->GLOBAL_CFG1_REG,
|
||
|
sensor_eng[0]->GLOBAL_CFG3_REG,
|
||
|
sensor_eng[0]->GLOBAL_CFG0_REG,
|
||
|
sensor_eng[0]->SLV0_INTR_MASK);
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|