初版
This commit is contained in:
@@ -0,0 +1,495 @@
|
||||
#ifdef SUPPORT_MS_EXTENSIONS
|
||||
#pragma bss_seg(".iic_api.data.bss")
|
||||
#pragma data_seg(".iic_api.data")
|
||||
#pragma const_seg(".iic_api.text.const")
|
||||
#pragma code_seg(".iic_api.text")
|
||||
#endif
|
||||
#include "iic_api.h"
|
||||
#include "asm/wdt.h"
|
||||
#include "atomic.h"
|
||||
#include "init.h"
|
||||
|
||||
#define LOG_TAG_CONST IIC
|
||||
#define LOG_TAG "[iic_api]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
static OS_MUTEX iic_mutex[2] = {0};
|
||||
static atomic_t iic_ref[2];
|
||||
//********************hw-iic for tp/alipay se/compass**********************//
|
||||
int iic_api_init(void)
|
||||
{
|
||||
os_mutex_create(&iic_mutex[0]);
|
||||
os_mutex_create(&iic_mutex[1]);
|
||||
return 0;
|
||||
}
|
||||
platform_initcall(iic_api_init);
|
||||
|
||||
|
||||
int system_iic_init(hw_iic_dev iic, struct iic_master_config *i2c_config)
|
||||
{
|
||||
int ret = 0;
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
ASSERT(!config_asser || (atomic_read(&iic_ref[iic]) == 0));
|
||||
if (atomic_inc_return(&iic_ref[iic]) == 1) {
|
||||
|
||||
ret = hw_iic_init(iic, i2c_config);
|
||||
}
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int system_iic_deinit(hw_iic_dev iic)
|
||||
{
|
||||
int ret = 0;
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
if (atomic_read(&iic_ref[iic]) != 0 && atomic_dec_return(&iic_ref[iic])) {
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
return ret;
|
||||
}
|
||||
ret = hw_iic_deinit(iic);
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void system_iic_reset(hw_iic_dev iic)
|
||||
{
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
|
||||
hw_iic_reset(iic);
|
||||
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
}
|
||||
|
||||
int system_iic_suspend(hw_iic_dev iic)
|
||||
{
|
||||
int ret;
|
||||
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
ret = hw_iic_suspend(iic);
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int system_iic_resume(hw_iic_dev iic)
|
||||
{
|
||||
int ret;
|
||||
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
ret = hw_iic_resume(iic);
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int system_iic_read_nbytes(hw_iic_dev iic,
|
||||
unsigned char dev_7bit_addr, //7位设备地址
|
||||
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
||||
unsigned char *read_buf, int read_len)//缓存buf,读取长度
|
||||
{
|
||||
int ret;
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
|
||||
ret = hw_i2c_master_read_nbytes_from_device_reg(iic, dev_7bit_addr << 1, reg_addr, reg_len, read_buf, read_len);
|
||||
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int system_iic_write_nbytes(hw_iic_dev iic,
|
||||
unsigned char dev_7bit_addr, //7位设备地址
|
||||
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
||||
unsigned char *write_buf, int write_len)//数据buf, 写入长度
|
||||
{
|
||||
int ret;
|
||||
os_mutex_pend(&iic_mutex[iic], 0);
|
||||
|
||||
ret = hw_i2c_master_write_nbytes_to_device_reg(iic, dev_7bit_addr << 1, reg_addr, reg_len, write_buf, write_len);
|
||||
|
||||
os_mutex_post(&iic_mutex[iic]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/******************************soft iic*****************************/
|
||||
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
||||
//return: <0:error, =read_len:ok
|
||||
int soft_i2c_master_read_nbytes_from_device_reg(soft_iic_dev iic,
|
||||
unsigned char dev_addr, //设备地址
|
||||
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
||||
unsigned char *read_buf, int read_len)//缓存buf,读取长度
|
||||
{
|
||||
u8 ack;
|
||||
int ret = 0;
|
||||
if (soft_iic_check_busy(iic) != IIC_OK) { //busy
|
||||
ret = IIC_ERROR_BUSY; //busy
|
||||
goto _read_exit2;
|
||||
}
|
||||
soft_iic_start(iic);
|
||||
|
||||
if ((reg_addr != NULL) && (reg_len != 0)) {
|
||||
ack = soft_iic_tx_byte(iic, dev_addr);
|
||||
if (ack == 0) {
|
||||
log_error("dev_addr no ack!");
|
||||
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
||||
goto _read_exit1;
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < reg_len; i++) {
|
||||
ack = soft_iic_tx_byte(iic, reg_addr[i]);
|
||||
if (ack == 0) {
|
||||
log_error("reg_addr no ack!");
|
||||
ret = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
||||
goto _read_exit1;
|
||||
}
|
||||
}
|
||||
soft_iic_start(iic);
|
||||
}
|
||||
|
||||
ack = soft_iic_tx_byte(iic, dev_addr | BIT(0));
|
||||
if (ack == 0) {
|
||||
log_error("dev_addr no ack!");
|
||||
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
||||
goto _read_exit1;
|
||||
}
|
||||
|
||||
ret = soft_iic_read_buf(iic, read_buf, read_len);
|
||||
_read_exit1:
|
||||
soft_iic_stop(iic);
|
||||
_read_exit2:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
||||
//return: =write_len:ok, other:error
|
||||
int soft_i2c_master_write_nbytes_to_device_reg(soft_iic_dev iic,
|
||||
unsigned char dev_addr, //设备地址
|
||||
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
||||
unsigned char *write_buf, int write_len)//数据buf, 写入长度
|
||||
{
|
||||
int res;
|
||||
u8 ack;
|
||||
if (soft_iic_check_busy(iic) != IIC_OK) { //busy
|
||||
res = IIC_ERROR_BUSY; //busy
|
||||
goto _write_exit2;
|
||||
}
|
||||
|
||||
soft_iic_start(iic);
|
||||
ack = soft_iic_tx_byte(iic, dev_addr);
|
||||
if (ack == 0) {
|
||||
log_error("dev_addr no ack!");
|
||||
res = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
||||
goto _write_exit1;
|
||||
}
|
||||
|
||||
if ((reg_addr != NULL) && (reg_len != 0)) {
|
||||
for (u8 i = 0; i < reg_len; i++) {
|
||||
ack = soft_iic_tx_byte(iic, reg_addr[i]);
|
||||
if (ack == 0) {
|
||||
log_error("reg_addr no ack!");
|
||||
res = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
||||
goto _write_exit1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (res = 0; res < write_len; res++) {
|
||||
if (0 == soft_iic_tx_byte(iic, write_buf[res])) {
|
||||
log_error("write data no ack!");
|
||||
goto _write_exit1;
|
||||
}
|
||||
}
|
||||
_write_exit1:
|
||||
soft_iic_stop(iic);
|
||||
_write_exit2:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************hw iic master*****************************/
|
||||
#if defined CONFIG_IIC_VERSION2
|
||||
#define HW_IIC_MASTER_ISR_EN 1
|
||||
#else
|
||||
#define HW_IIC_MASTER_ISR_EN 0
|
||||
#endif
|
||||
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
||||
//return: other:error, =read_len:ok
|
||||
int hw_i2c_master_read_nbytes_from_device_reg(hw_iic_dev iic,
|
||||
unsigned char dev_addr, //设备地址
|
||||
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
||||
unsigned char *read_buf, int read_len)//缓存buf,读取长度
|
||||
{
|
||||
#if HW_IIC_MASTER_ISR_EN
|
||||
#if defined(P11_HW_IIC_NUM)&&P11_HW_IIC_NUM
|
||||
if (iic != HW_P11_IIC_0)
|
||||
#endif
|
||||
{
|
||||
struct hw_iic_master_isr_transmit iic_isr_info = {
|
||||
.dev_addr = dev_addr,
|
||||
.restart_flag = 1,
|
||||
.reg_buf = reg_addr,
|
||||
.reg_len = reg_len,
|
||||
.data_buf = read_buf,
|
||||
.rx_len = read_len,
|
||||
.tx_len = 0,
|
||||
};
|
||||
if ((reg_addr == NULL) || (reg_len == 0)) {
|
||||
iic_isr_info .dev_addr = dev_addr | BIT(0);
|
||||
iic_isr_info .restart_flag = 0;
|
||||
}
|
||||
enum iic_state_enum iic_sta = hw_iic_master_isr_transmit_cfg(iic, &iic_isr_info, 20);//byte间隔超时20:20*30ms
|
||||
if (iic_sta != IIC_OK) {
|
||||
log_error("iic%d isr sta:%d\n", iic, iic_sta);
|
||||
if (iic_sta == IIC_ERROR_MASTER_ERROR) {
|
||||
hw_iic_reset(iic);
|
||||
}
|
||||
return iic_sta;
|
||||
}
|
||||
return iic_isr_info.xfer_postion;
|
||||
}
|
||||
#endif
|
||||
|
||||
u8 ack;
|
||||
int ret = 0;
|
||||
if (hw_iic_check_busy(iic) != IIC_OK) { //busy
|
||||
ret = IIC_ERROR_BUSY; //busy
|
||||
goto _read_exit2;
|
||||
}
|
||||
ret = hw_iic_start(iic);
|
||||
if (ret < 0) {
|
||||
log_error("iic lock busy!%d", ret);
|
||||
goto _read_exit2;
|
||||
}
|
||||
|
||||
if ((reg_addr != NULL) && (reg_len != 0)) {
|
||||
ack = hw_iic_tx_byte(iic, dev_addr);
|
||||
if (ack == 0) {
|
||||
log_error("dev_addr no ack!");
|
||||
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
||||
goto _read_exit1;
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < reg_len; i++) {
|
||||
ack = hw_iic_tx_byte(iic, reg_addr[i]);
|
||||
if (ack == 0) {
|
||||
log_error("reg_addr no ack!");
|
||||
ret = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
||||
goto _read_exit1;
|
||||
}
|
||||
}
|
||||
hw_iic_start(iic);
|
||||
}
|
||||
|
||||
ack = hw_iic_tx_byte(iic, dev_addr | BIT(0));
|
||||
if (ack == 0) {
|
||||
log_error("dev_addr no ack!");
|
||||
ret = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
||||
goto _read_exit1;
|
||||
}
|
||||
|
||||
ret = hw_iic_read_buf(iic, read_buf, read_len);
|
||||
_read_exit1:
|
||||
hw_iic_stop(iic);
|
||||
if (ret != read_len) {
|
||||
hw_iic_err_reset(iic);
|
||||
hw_iic_reset(iic);
|
||||
}
|
||||
_read_exit2:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//如果无reg_addr:reg_addr=NULL,reg_len=0
|
||||
//return: =write_len:ok, other:error
|
||||
int hw_i2c_master_write_nbytes_to_device_reg(hw_iic_dev iic,
|
||||
unsigned char dev_addr, //设备地址
|
||||
unsigned char *reg_addr, unsigned char reg_len,//设备寄存器地址,长度
|
||||
unsigned char *write_buf, int write_len)//数据buf, 写入长度
|
||||
{
|
||||
#if HW_IIC_MASTER_ISR_EN
|
||||
#if defined(P11_HW_IIC_NUM)&&P11_HW_IIC_NUM
|
||||
if (iic != HW_P11_IIC_0)
|
||||
#endif
|
||||
{
|
||||
struct hw_iic_master_isr_transmit iic_isr_info = {
|
||||
.dev_addr = dev_addr,
|
||||
.restart_flag = 0,
|
||||
.reg_buf = reg_addr,
|
||||
.reg_len = reg_len,
|
||||
.data_buf = write_buf,
|
||||
.rx_len = 0,
|
||||
.tx_len = write_len,
|
||||
};
|
||||
enum iic_state_enum iic_sta = hw_iic_master_isr_transmit_cfg(iic, &iic_isr_info, 20);//byte间隔超时20:20*30ms
|
||||
if (iic_sta != IIC_OK) {
|
||||
log_error("iic%d isr sta:%d\n", iic, iic_sta);
|
||||
if (iic_sta == IIC_ERROR_MASTER_ERROR) {
|
||||
hw_iic_reset(iic);
|
||||
}
|
||||
return iic_sta;
|
||||
}
|
||||
return iic_isr_info.xfer_postion;
|
||||
}
|
||||
#endif
|
||||
|
||||
int res;
|
||||
u8 ack;
|
||||
if (hw_iic_check_busy(iic) != IIC_OK) { //busy
|
||||
res = IIC_ERROR_BUSY; //busy
|
||||
goto _write_exit2;
|
||||
}
|
||||
|
||||
res = hw_iic_start(iic);
|
||||
if (res < 0) {
|
||||
log_error("iic lock busy!%d", res);
|
||||
goto _write_exit2;
|
||||
}
|
||||
ack = hw_iic_tx_byte(iic, dev_addr);
|
||||
if (ack == 0) {
|
||||
log_error("dev_addr no ack!");
|
||||
res = IIC_ERROR_DEV_ADDR_ACK_ERROR; //无应答
|
||||
goto _write_exit1;
|
||||
}
|
||||
|
||||
if ((reg_addr != NULL) && (reg_len != 0)) {
|
||||
for (u8 i = 0; i < reg_len; i++) {
|
||||
ack = hw_iic_tx_byte(iic, reg_addr[i]);
|
||||
if (ack == 0) {
|
||||
log_error("reg_addr no ack!");
|
||||
res = IIC_ERROR_REG_ADDR_ACK_ERROR; //无应答
|
||||
goto _write_exit1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (res = 0; res < write_len; res++) {
|
||||
if (0 == hw_iic_tx_byte(iic, write_buf[res])) {
|
||||
log_error("write data no ack!");
|
||||
goto _write_exit1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
res = hw_iic_write_buf(iic, write_buf, write_len);
|
||||
#endif
|
||||
_write_exit1:
|
||||
hw_iic_stop(iic);
|
||||
if (res != write_len) {
|
||||
hw_iic_err_reset(iic);
|
||||
hw_iic_reset(iic);
|
||||
}
|
||||
_write_exit2:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************hw iic slave*****************************/
|
||||
|
||||
//rx协议:start,addr write,data0,data1,,,,,,stop
|
||||
int hw_iic_slave_polling_rx(hw_iic_dev iic, u8 *rx_buf)
|
||||
{
|
||||
int rx_cnt = 0;
|
||||
int rx_state = 0;
|
||||
|
||||
log_info("--iic slave polling rx --");
|
||||
local_irq_disable();//关闭所有中断
|
||||
rx_state = hw_iic_slave_rx_prepare(iic, 0, 600000);//1s
|
||||
if (rx_state == IIC_SLAVE_RX_PREPARE_OK) { //rx
|
||||
} else if (rx_state == IIC_SLAVE_RX_PREPARE_TIMEOUT) { //error
|
||||
log_error("iic slave wait addr timeout!");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
} else if (rx_state == IIC_SLAVE_RX_PREPARE_END_OK) { //end
|
||||
log_error("iic slave wait end!");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
rx_state = hw_iic_slave_rx_byte(iic, &rx_buf[0]);//addr
|
||||
if (rx_state >= IIC_SLAVE_RX_ADDR_RX) { //rx
|
||||
} else if (rx_state == IIC_SLAVE_RX_ADDR_NO_MATCH) { //error
|
||||
log_error("iic slave rx addr error!");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
} else if (rx_state == IIC_SLAVE_RX_ADDR_TX) { //tx
|
||||
|
||||
}
|
||||
rx_state = hw_iic_slave_rx_prepare(iic, 1, 100000);//1s, 1:收到数据应答
|
||||
if (rx_state == IIC_SLAVE_RX_PREPARE_OK) { //rx
|
||||
} else if (rx_state == IIC_SLAVE_RX_PREPARE_TIMEOUT) { //error
|
||||
log_error("iic slave wait reg timeout!");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
} else if (rx_state == IIC_SLAVE_RX_PREPARE_END_OK) { //end
|
||||
log_info("iic slave wait end!");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
rx_cnt = hw_iic_slave_rx_nbyte(iic, &rx_buf[1]);
|
||||
local_irq_enable();
|
||||
/* log_info("rx addr:%x, slave addr:%x", rx_buf[0], hw_iic_slave_get_addr(iic)); */
|
||||
rx_cnt++;
|
||||
log_info_hexdump(rx_buf, rx_cnt);
|
||||
log_info("~~~~~iic rx polling end~~~~~\n");
|
||||
memset(rx_buf, 0, rx_cnt);
|
||||
return rx_cnt;
|
||||
}
|
||||
|
||||
//tx协议:start,addr read,data0,data1,,,,,nack,stop
|
||||
int hw_iic_slave_polling_tx(hw_iic_dev iic, u8 *tx_buf)
|
||||
{
|
||||
u8 slave_rx_data[3] = {0, 0, 0};
|
||||
int rx_cnt = 0, tx_cnt = 0;
|
||||
int rx_state = 0;
|
||||
log_info("--iic slave polling tx --");
|
||||
local_irq_disable();//关闭所有中断
|
||||
rx_state = hw_iic_slave_rx_prepare(iic, 0, 600000);//1s
|
||||
if (rx_state == IIC_SLAVE_RX_PREPARE_OK) { //rx
|
||||
} else if (rx_state == IIC_SLAVE_RX_PREPARE_TIMEOUT) { //error
|
||||
log_error("iic slave wait addr timeout!\n");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
} else if (rx_state == IIC_SLAVE_RX_PREPARE_END_OK) { //end
|
||||
log_error("iic slave wait end!\n");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
rx_state = hw_iic_slave_rx_byte(iic, &slave_rx_data[rx_cnt++]);//addr
|
||||
if (rx_state >= IIC_SLAVE_RX_ADDR_RX) { //rx
|
||||
} else if (rx_state == IIC_SLAVE_RX_ADDR_TX) { //tx
|
||||
hw_iic_slave_tx_byte(iic, tx_buf[tx_cnt++]);
|
||||
goto _tx_strat;
|
||||
} else { //error
|
||||
log_error("iic slave rx addr error!\n");
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
_tx_strat:
|
||||
tx_cnt = hw_iic_slave_tx_nbyte(iic, &tx_buf[tx_cnt]);
|
||||
|
||||
local_irq_enable();
|
||||
/* log_info("rx0 addr:%x, slave addr:%x", slave_rx_data[0], hw_iic_slave_get_addr(iic)); */
|
||||
log_info_hexdump(slave_rx_data, rx_cnt);
|
||||
log_info("~~~~~iic tx polling end~~~~~\n");
|
||||
return tx_cnt + 1; //ok
|
||||
}
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
#ifdef SUPPORT_MS_EXTENSIONS
|
||||
#pragma bss_seg(".iic_soft.data.bss")
|
||||
#pragma data_seg(".iic_soft.data")
|
||||
#pragma const_seg(".iic_soft.text.const")
|
||||
#pragma code_seg(".iic_soft.text")
|
||||
#endif
|
||||
#include "iic_soft.h"
|
||||
#include "clock.h"
|
||||
|
||||
#define LOG_TAG_CONST IIC
|
||||
#define LOG_TAG "[iic_soft]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
static u8 soft_iic_state[MAX_SOFT_IIC_NUM];
|
||||
static struct iic_master_config soft_iic_cfg_cache[MAX_SOFT_IIC_NUM];
|
||||
|
||||
//input pull up
|
||||
#define IIC_SCL_H(scl) \
|
||||
gpio_set_mode(scl/16, BIT(scl%16), soft_iic_cfg_cache[iic].io_mode)
|
||||
|
||||
#define IIC_SCL_L(scl) \
|
||||
gpio_set_mode(scl/16, BIT(scl%16), PORT_OUTPUT_LOW)
|
||||
|
||||
|
||||
#define IIC_SDA_DIR(sda, val) \
|
||||
if (val){ \
|
||||
gpio_set_mode(IO_PORT_SPILT(sda), soft_iic_cfg_cache[iic].io_mode); \
|
||||
} else { \
|
||||
gpio_set_mode(IO_PORT_SPILT(sda), PORT_OUTPUT_LOW); \
|
||||
}
|
||||
|
||||
//input pull up
|
||||
#define IIC_SDA_H(sda) \
|
||||
gpio_set_mode(sda/16, BIT(sda%16), soft_iic_cfg_cache[iic].io_mode)
|
||||
|
||||
#define IIC_SDA_L(sda) \
|
||||
gpio_set_mode(sda/16, BIT(sda%16), PORT_OUTPUT_LOW)
|
||||
|
||||
#define IIC_SDA_READ(sda) \
|
||||
gpio_read(sda)
|
||||
|
||||
#define soft_iic_delay(num) \
|
||||
delay_cnt= num; \
|
||||
while (delay_cnt--) { \
|
||||
asm("nop"); \
|
||||
}
|
||||
static inline u32 iic_get_delay(soft_iic_dev iic)
|
||||
{
|
||||
/* u32 hsb_clk = clk_get("sys"); */
|
||||
u32 delay_num = 0;
|
||||
return delay_num;
|
||||
}
|
||||
|
||||
extern const struct iic_master_config soft_iic_cfg_const[MAX_SOFT_IIC_NUM];
|
||||
struct iic_master_config *get_soft_iic_config(soft_iic_dev iic)
|
||||
{
|
||||
return (struct iic_master_config *)&soft_iic_cfg_const[iic];
|
||||
}
|
||||
enum iic_state_enum soft_iic_init(soft_iic_dev iic, struct iic_master_config *i2c_config)
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
if (i2c_config == NULL) {
|
||||
log_error("soft iic%d param error!\n", iic);
|
||||
return IIC_ERROR_PARAM_ERROR;
|
||||
}
|
||||
if (iic >= MAX_SOFT_IIC_NUM) {
|
||||
log_error("soft iic index:%d error!\n", iic);
|
||||
return IIC_ERROR_INDEX_ERROR;
|
||||
}
|
||||
if ((soft_iic_state[iic]&BIT(7)) != 0) {
|
||||
log_error("soft iic%d has been occupied!\n", iic);
|
||||
return IIC_ERROR_INIT_FAIL;
|
||||
}
|
||||
soft_iic_state[iic] = BIT(7);//init ok
|
||||
memcpy(&soft_iic_cfg_cache[iic], i2c_config, sizeof(struct iic_master_config));
|
||||
|
||||
//freq:
|
||||
|
||||
gpio_set_mode(IO_PORT_SPILT(i2c_config->scl_io), i2c_config->io_mode); //默认10k
|
||||
gpio_set_mode(IO_PORT_SPILT(i2c_config->sda_io), i2c_config->io_mode); //默认10k
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(i2c_config->scl_io), i2c_config->hdrive);
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(i2c_config->sda_io), i2c_config->hdrive);
|
||||
return IIC_OK;//ok
|
||||
}
|
||||
|
||||
enum iic_state_enum soft_iic_deinit(soft_iic_dev iic)
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
if (soft_iic_state[iic] == 0) {
|
||||
log_error("soft iic%d has been no init!\n", iic);
|
||||
return IIC_ERROR_NO_INIT;
|
||||
}
|
||||
soft_iic_state[iic] = 0;//no init
|
||||
|
||||
gpio_set_mode(IO_PORT_SPILT(soft_iic_cfg_cache[iic].scl_io), PORT_HIGHZ);
|
||||
gpio_set_mode(IO_PORT_SPILT(soft_iic_cfg_cache[iic].sda_io), PORT_HIGHZ);
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(soft_iic_cfg_cache[iic].scl_io), PORT_DRIVE_STRENGT_2p4mA);
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(soft_iic_cfg_cache[iic].sda_io), PORT_DRIVE_STRENGT_2p4mA);
|
||||
return IIC_OK;//ok
|
||||
}
|
||||
|
||||
enum iic_state_enum soft_iic_suspend(soft_iic_dev iic)
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
if ((soft_iic_state[iic] & 0xc0) != 0x80) {
|
||||
log_error("soft iic%d is no init or suspend!\n", iic);
|
||||
return IIC_ERROR_SUSPEND_FAIL;
|
||||
}
|
||||
if ((soft_iic_state[iic] & 0x3f) != 0) {
|
||||
log_error("soft iic%d is busy!\n", iic);
|
||||
return IIC_ERROR_BUSY;
|
||||
}
|
||||
soft_iic_state[iic] |= BIT(6);//suspend ok
|
||||
gpio_set_mode(IO_PORT_SPILT(soft_iic_cfg_cache[iic].scl_io), PORT_HIGHZ);
|
||||
gpio_set_mode(IO_PORT_SPILT(soft_iic_cfg_cache[iic].sda_io), PORT_HIGHZ);
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(soft_iic_cfg_cache[iic].scl_io), PORT_DRIVE_STRENGT_2p4mA);
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(soft_iic_cfg_cache[iic].sda_io), PORT_DRIVE_STRENGT_2p4mA);
|
||||
return IIC_OK;//ok
|
||||
}
|
||||
|
||||
enum iic_state_enum soft_iic_resume(soft_iic_dev iic)
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
if ((soft_iic_state[iic] & 0xc0) != 0xc0) {
|
||||
log_error("soft iic%d is no init or no suspend!\n", iic);
|
||||
return IIC_ERROR_RESUME_FAIL;
|
||||
}
|
||||
soft_iic_state[iic] &= ~ BIT(6); //resume ok
|
||||
|
||||
gpio_set_mode(IO_PORT_SPILT(soft_iic_cfg_cache[iic].scl_io), soft_iic_cfg_cache[iic].io_mode); //默认10k
|
||||
gpio_set_mode(IO_PORT_SPILT(soft_iic_cfg_cache[iic].sda_io), soft_iic_cfg_cache[iic].io_mode); //默认10k
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(soft_iic_cfg_cache[iic].scl_io), soft_iic_cfg_cache[iic].hdrive);
|
||||
gpio_set_drive_strength(IO_PORT_SPILT(soft_iic_cfg_cache[iic].sda_io), soft_iic_cfg_cache[iic].hdrive);
|
||||
return IIC_OK;//ok
|
||||
}
|
||||
|
||||
//return:0:error, 1:ok
|
||||
enum iic_state_enum soft_iic_check_busy(soft_iic_dev iic)
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
if (soft_iic_state[iic] & 0x0f) {
|
||||
return IIC_ERROR_BUSY;//error
|
||||
}
|
||||
soft_iic_state[iic]++;//busy
|
||||
return IIC_OK;//ok
|
||||
}
|
||||
void soft_iic_idle(soft_iic_dev iic)
|
||||
{
|
||||
soft_iic_state[iic] &= 0xf0;//idle
|
||||
}
|
||||
|
||||
enum iic_state_enum soft_iic_start(soft_iic_dev iic)
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
/* printf("soft_iic_init hsb clock:%d, delay cnt:%d\n",clk_get("sys"),dly_t); */
|
||||
|
||||
IIC_SDA_H(soft_iic_cfg_cache[iic].sda_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t * 2);
|
||||
|
||||
IIC_SDA_L(soft_iic_cfg_cache[iic].sda_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
return IIC_OK;//ok
|
||||
}
|
||||
|
||||
void soft_iic_stop(soft_iic_dev iic)
|
||||
{
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
IIC_SDA_L(soft_iic_cfg_cache[iic].sda_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t * 2);
|
||||
|
||||
IIC_SDA_H(soft_iic_cfg_cache[iic].sda_io);
|
||||
soft_iic_delay(dly_t);
|
||||
soft_iic_idle(iic);
|
||||
}
|
||||
|
||||
void soft_iic_reset(soft_iic_dev iic)//同iic_v2
|
||||
{
|
||||
ASSERT(iic < MAX_SOFT_IIC_NUM, "iic > MAX_SOFT_IIC_NUM");
|
||||
soft_iic_start(iic);
|
||||
soft_iic_stop(iic);
|
||||
soft_iic_idle(iic);
|
||||
}
|
||||
|
||||
static u8 soft_iic_check_ack(soft_iic_dev iic)
|
||||
{
|
||||
u8 ack;
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
|
||||
IIC_SDA_DIR(soft_iic_cfg_cache[iic].sda_io, 1);
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
if (IIC_SDA_READ(soft_iic_cfg_cache[iic].sda_io) == 0) {
|
||||
ack = 1;
|
||||
} else {
|
||||
ack = 0;
|
||||
}
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
IIC_SDA_DIR(soft_iic_cfg_cache[iic].sda_io, 0);
|
||||
IIC_SDA_L(soft_iic_cfg_cache[iic].sda_io);
|
||||
|
||||
return ack;//1:有应答, 0:无
|
||||
}
|
||||
|
||||
static void soft_iic_rx_ack(soft_iic_dev iic)
|
||||
{
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
IIC_SDA_L(soft_iic_cfg_cache[iic].sda_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t * 2);
|
||||
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
}
|
||||
|
||||
static void soft_iic_rx_nack(soft_iic_dev iic)
|
||||
{
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
IIC_SDA_H(soft_iic_cfg_cache[iic].sda_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t * 2);
|
||||
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
}
|
||||
|
||||
u8 soft_iic_tx_byte(soft_iic_dev iic, u8 byte)
|
||||
{
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
|
||||
local_irq_disable();
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
for (u32 i = 0; i < 8; i++) { //MSB FIRST
|
||||
if ((byte << i) & 0x80) {
|
||||
IIC_SDA_H(soft_iic_cfg_cache[iic].sda_io);
|
||||
} else {
|
||||
IIC_SDA_L(soft_iic_cfg_cache[iic].sda_io);
|
||||
}
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t * 2);
|
||||
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
}
|
||||
u8 ack = soft_iic_check_ack(iic);//1:有应答, 0:无
|
||||
local_irq_enable();
|
||||
return ack;
|
||||
}
|
||||
|
||||
u8 soft_iic_rx_byte(soft_iic_dev iic, u8 ack, s8 *err)
|
||||
{
|
||||
u32 delay_cnt;
|
||||
u32 dly_t = iic_get_delay(iic);
|
||||
u8 byte = 0;
|
||||
|
||||
local_irq_disable();
|
||||
IIC_SDA_DIR(soft_iic_cfg_cache[iic].sda_io, 1);
|
||||
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_H(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
byte = byte << 1;
|
||||
if (IIC_SDA_READ(soft_iic_cfg_cache[iic].sda_io)) {
|
||||
byte |= 1;
|
||||
}
|
||||
soft_iic_delay(dly_t);
|
||||
|
||||
IIC_SCL_L(soft_iic_cfg_cache[iic].scl_io);
|
||||
soft_iic_delay(dly_t);
|
||||
}
|
||||
|
||||
IIC_SDA_DIR(soft_iic_cfg_cache[iic].sda_io, 0);
|
||||
if (ack) {
|
||||
soft_iic_rx_ack(iic);
|
||||
} else {
|
||||
soft_iic_rx_nack(iic);
|
||||
}
|
||||
|
||||
local_irq_enable();
|
||||
if (err) {
|
||||
*err = IIC_OK;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
//return: =len:ok
|
||||
int soft_iic_read_buf(soft_iic_dev iic, void *buf, int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!buf || !len) {
|
||||
return IIC_ERROR_PARAM_ERROR;
|
||||
}
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
((u8 *)buf)[i] = soft_iic_rx_byte(iic, 1, NULL);
|
||||
}
|
||||
((u8 *)buf)[len - 1] = soft_iic_rx_byte(iic, 0, NULL);
|
||||
return len;
|
||||
}
|
||||
|
||||
//return: =len:ok
|
||||
int soft_iic_write_buf(soft_iic_dev iic, const void *buf, int len)
|
||||
{
|
||||
int i;
|
||||
u8 ack;
|
||||
|
||||
if (!buf || !len) {
|
||||
return IIC_ERROR_PARAM_ERROR;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
ack = soft_iic_tx_byte(iic, ((u8 *)buf)[i]);
|
||||
if (ack == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "ir_decoder.h"
|
||||
#include "jiffies.h"
|
||||
|
||||
#define LOG_TAG_CONST PERI
|
||||
#define LOG_TAG "[ir_decode]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define NEC_NBITS 32
|
||||
#define NEC_TIME_DEVIATION 10 //允许10%偏差
|
||||
#define NEC_UNIT_TIME 563
|
||||
#define NEC_HEADER_TIME ((16 + 8) * NEC_UNIT_TIME)
|
||||
#define NEC_BIT_0_TIME ((1 + 1) * NEC_UNIT_TIME)
|
||||
#define NEC_BIT_1_TIME ((3 + 1) * NEC_UNIT_TIME)
|
||||
#define NEC_REPEAT_TIME ((16 + 4) * NEC_UNIT_TIME)
|
||||
#define NEC_TIMEOUT_MS 150 //150ms
|
||||
|
||||
enum nec_data_type {
|
||||
NEC_ERROR = 0,
|
||||
NEC_HEAD,
|
||||
NEC_BIT_1,
|
||||
NEC_BIT_0,
|
||||
NEC_REPEAT,
|
||||
};
|
||||
struct ir_decode_t {
|
||||
u32 jiffies; //记录当前系统时间
|
||||
u32 ir_data; //存储接收到的红外数据,4*8bit = (cmd_not + cmd +addr_not + addr)
|
||||
u8 capture_tid; //用于捕获功能的tiemr_id
|
||||
u8 bit_count; //有效bit个数
|
||||
u8 command_count; //有效命令个数
|
||||
};
|
||||
static struct ir_decode_t _ir_decode;
|
||||
static struct ir_decode_t *ir_decode = &_ir_decode;
|
||||
static u32 get_cur_jiffies()
|
||||
{
|
||||
return jiffies;
|
||||
}
|
||||
static u32 jiffies_timeout_check()
|
||||
{
|
||||
u32 jiffies_cur = get_cur_jiffies();
|
||||
int jiffies_diff = jiffies_cur - ir_decode->jiffies;
|
||||
ir_decode->jiffies = jiffies_cur;
|
||||
//判断是否溢出
|
||||
if (jiffies_diff < 0) {
|
||||
jiffies_diff += 0xffffffff;
|
||||
}
|
||||
//判断两次下降沿间隔时间是否超时
|
||||
if (jiffies_to_msecs(jiffies_diff) >= NEC_TIMEOUT_MS) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static u32 is_time_within(u32 t, u32 center, u32 deviation)
|
||||
{
|
||||
if (__builtin_abs(((int)t - (int)center)) < (center * deviation / 100)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static u32 ir_decoder_pulse_check(u32 us)
|
||||
{
|
||||
u32 type;
|
||||
if (is_time_within(us, NEC_HEADER_TIME, NEC_TIME_DEVIATION)) {
|
||||
type = NEC_HEAD;
|
||||
} else if (is_time_within(us, NEC_BIT_0_TIME, NEC_TIME_DEVIATION)) {
|
||||
type = NEC_BIT_0;
|
||||
} else if (is_time_within(us, NEC_BIT_1_TIME, NEC_TIME_DEVIATION)) {
|
||||
type = NEC_BIT_1;
|
||||
} else if (is_time_within(us, NEC_REPEAT_TIME, NEC_TIME_DEVIATION)) {
|
||||
type = NEC_REPEAT;
|
||||
} else {
|
||||
type = NEC_ERROR;
|
||||
}
|
||||
log_debug("us = %d, type = %d\n", us, type);
|
||||
return type;
|
||||
}
|
||||
static void ir_decoder_bit_count_check()
|
||||
{
|
||||
if (ir_decode->bit_count == NEC_NBITS) {
|
||||
ir_decode->command_count++;
|
||||
log_debug("ir_data:0x%08x, command_count:%d\n", ir_decode->ir_data, ir_decode->command_count);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_decode_irq(u32 tid, void *arg)
|
||||
{
|
||||
u32 us = gptimer_get_capture_cnt2us(tid);
|
||||
//超时或第一个边沿直接退出
|
||||
if (jiffies_timeout_check()) {
|
||||
return;
|
||||
}
|
||||
u32 type = ir_decoder_pulse_check(us);
|
||||
|
||||
switch (type) {
|
||||
case NEC_HEAD:
|
||||
ir_decode->bit_count = 0;
|
||||
ir_decode->command_count = 0;
|
||||
break;
|
||||
case NEC_BIT_1:
|
||||
ir_decode->ir_data >>= 1;
|
||||
ir_decode->ir_data |= 0x80000000;
|
||||
ir_decode->bit_count++;
|
||||
ir_decoder_bit_count_check();
|
||||
break;
|
||||
case NEC_BIT_0:
|
||||
ir_decode->ir_data >>= 1;
|
||||
ir_decode->bit_count++;
|
||||
ir_decoder_bit_count_check();
|
||||
break;
|
||||
case NEC_REPEAT:
|
||||
ir_decoder_bit_count_check();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ir_decoder_init(const struct gptimer_config *gt_cfg)
|
||||
{
|
||||
log_info("%s()\n", __func__);
|
||||
memset(ir_decode, 0, sizeof(struct ir_decode_t));
|
||||
ir_decode->jiffies = get_cur_jiffies();
|
||||
#ifdef TCFG_IR_DECODER_TID
|
||||
ir_decode->capture_tid = gptimer_init(TCFG_IR_DECODER_TID, gt_cfg); //用户配置固定timer
|
||||
#else
|
||||
ir_decode->capture_tid = gptimer_init(TIMERx, gt_cfg); //内部分配空闲timer
|
||||
#endif
|
||||
log_info("ir_decode->capture_tid = %d\n", ir_decode->capture_tid);
|
||||
if (gt_cfg->mode == GPTIMER_MODE_CAPTURE_EDGE_RISE) {
|
||||
gpio_set_mode(gt_cfg->capture.port, gt_cfg->capture.pin, PORT_INPUT_PULLDOWN_10K);//开下拉
|
||||
} else if (gt_cfg->mode == GPTIMER_MODE_CAPTURE_EDGE_FALL) {
|
||||
gpio_set_mode(gt_cfg->capture.port, gt_cfg->capture.pin, PORT_INPUT_PULLUP_10K);//开上拉
|
||||
}
|
||||
if (gt_cfg->irq_cb == NULL) {
|
||||
gptimer_set_irq_callback(ir_decode->capture_tid, ir_decode_irq);
|
||||
}
|
||||
gptimer_start(ir_decode->capture_tid);
|
||||
}
|
||||
|
||||
void ir_decoder_deinit()
|
||||
{
|
||||
gptimer_deinit(ir_decode->capture_tid);
|
||||
}
|
||||
|
||||
u32 ir_decoder_get_data(void)
|
||||
{
|
||||
u32 data = -1;
|
||||
if (ir_decode->command_count) {
|
||||
ir_decode->command_count--;
|
||||
data = ir_decode->ir_data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
u32 ir_decoder_get_command_value(void)
|
||||
{
|
||||
u32 data = ir_decoder_get_data();
|
||||
if (data == -1) {
|
||||
return -1;
|
||||
}
|
||||
u8 cmd = (data >> 16) & 0xff;
|
||||
u8 cmd_not = (data >> 24) & 0xff;
|
||||
if ((cmd ^ cmd_not) != 0xff) {
|
||||
cmd = -1;
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
u32 ir_decoder_get_command_value_uncheck(void)
|
||||
{
|
||||
u32 data = ir_decoder_get_data();
|
||||
if (data == -1) {
|
||||
return -1;
|
||||
}
|
||||
u8 cmd = (data >> 16) & 0xff;
|
||||
return cmd;
|
||||
}
|
||||
u32 ir_decoder_get_address_value(void)
|
||||
{
|
||||
u32 data = ir_decoder_get_data();
|
||||
if (data == -1) {
|
||||
return -1;
|
||||
}
|
||||
u8 addr = (data >> 0) & 0xff;
|
||||
u8 addr_not = (data >> 8) & 0xff;
|
||||
if ((addr ^ addr_not) != 0xff) {
|
||||
addr = (u8) - 1;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
u32 ir_decoder_get_address_value_uncheck(void)
|
||||
{
|
||||
u32 data = ir_decoder_get_data();
|
||||
if (data == -1) {
|
||||
return -1;
|
||||
}
|
||||
u8 addr = (data >> 0) & 0xff;
|
||||
return addr;
|
||||
}
|
||||
void ir_decoder_dump()
|
||||
{
|
||||
printf("header:%d, header_min:%d, header_max:%d\n",
|
||||
NEC_HEADER_TIME, (NEC_HEADER_TIME * (100 - NEC_TIME_DEVIATION) / 100), (NEC_HEADER_TIME * (100 + NEC_TIME_DEVIATION) / 100));
|
||||
printf("bit0:%d, bit0_min:%d, bit0_max:%d\n",
|
||||
NEC_BIT_0_TIME, (NEC_BIT_0_TIME * (100 - NEC_TIME_DEVIATION) / 100), (NEC_BIT_0_TIME * (100 + NEC_TIME_DEVIATION) / 100));
|
||||
printf("bit1:%d, bit1_min:%d, bit1_max:%d\n",
|
||||
NEC_BIT_1_TIME, (NEC_BIT_1_TIME * (100 - NEC_TIME_DEVIATION) / 100), (NEC_BIT_1_TIME * (100 + NEC_TIME_DEVIATION) / 100));
|
||||
printf("repeat:%d, repeat_min:%d, repeat_max:%d\n",
|
||||
NEC_REPEAT_TIME, (NEC_REPEAT_TIME * (100 - NEC_TIME_DEVIATION) / 100), (NEC_REPEAT_TIME * (100 + NEC_TIME_DEVIATION) / 100));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
#include "ir_encoder.h"
|
||||
#include "gptimer.h"
|
||||
#include "asm/power_interface.h"
|
||||
|
||||
#define LOG_TAG_CONST PERI
|
||||
#define LOG_TAG "[ir_encode]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
#define IR_NEC_PULSE_UNIT 563
|
||||
#define IR_NEC_BIT_1_H 1
|
||||
#define IR_NEC_BIT_1_L 3
|
||||
#define IR_NEC_BIT_0_H 1
|
||||
#define IR_NEC_BIT_0_L 1
|
||||
#define IR_NEC_HEAD_H 16
|
||||
#define IR_NEC_HEAD_L 8
|
||||
#define IR_NEC_END_H 1
|
||||
#define IR_NEC_END_L 1
|
||||
#define IR_NEC_END_REPEAT_L 75//196
|
||||
#define IR_NEC_REPEAT_H 16
|
||||
#define IR_NEC_REPEAT_L 4
|
||||
#define IR_NEC_REPEAT_END_H 1
|
||||
#define IR_NEC_REPEAT_END_L 175
|
||||
#define IR_NEC_REPEAT 0x00FF00FF
|
||||
|
||||
enum state : u8 {
|
||||
IR_IDLE,
|
||||
IR_HEAD,
|
||||
IR_DATA,
|
||||
IR_END,
|
||||
IR_REPEAT,
|
||||
IR_REPEAT_END,
|
||||
};
|
||||
|
||||
enum : u8 {
|
||||
DATA_BIT0 = 0,
|
||||
DATA_BIT1,
|
||||
HEAD_BIT,
|
||||
END_BIT,
|
||||
REPEAT_BIT,
|
||||
REPEAT_END_BIT,
|
||||
};
|
||||
|
||||
struct ir_encode_info {
|
||||
u32 ir_data; //存储发送的红外数据,4*8bit = (cmd_not + cmd +addr_not + addr)
|
||||
enum state state; //状态机,记录当前发送处于哪个阶段
|
||||
u8 pwm_tid; //用于pwm功能的timer_id
|
||||
u8 timer_tid; //用于timer功能的timer_id
|
||||
u8 high_level_count; //高电平持续count个单位时间
|
||||
u8 low_level_count; //低电平持续count个单位时间
|
||||
u8 repeat_en; //重复码使能标志
|
||||
u8 pwm_high_ctrl: 1; //高电平使能标志位,避免重复开关
|
||||
u8 pwm_low_ctrl: 1; //低平使能标志位,避免重复开关
|
||||
u8 bit_count: 6; //已发送bit个数
|
||||
};
|
||||
|
||||
#define IR_ENCODER_MALLOC_ENABLE 0
|
||||
#if IR_ENCODER_MALLOC_ENABLE
|
||||
#include "malloc.h"
|
||||
#else
|
||||
static struct ir_encode_info _ir_encode;
|
||||
#endif
|
||||
static struct ir_encode_info *ir_encode;
|
||||
|
||||
static u32 ir_encoder_malloc()
|
||||
{
|
||||
#if IR_ENCODER_MALLOC_ENABLE
|
||||
ir_encode = (struct ir_encode_info *)malloc(sizeof(struct ir_encode_info));
|
||||
#else
|
||||
ir_encode = &_ir_encode;
|
||||
#endif
|
||||
memset(ir_encode, 0, sizeof(struct ir_encode_info));
|
||||
return 0;
|
||||
}
|
||||
static u32 ir_encoder_free()
|
||||
{
|
||||
memset(ir_encode, 0, sizeof(struct ir_encode_info));
|
||||
#if IR_ENCODER_MALLOC_ENABLE
|
||||
free(ir_encode);
|
||||
#else
|
||||
ir_encode = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u32 ir_pwm_ctrl()
|
||||
{
|
||||
if (ir_encode->pwm_high_ctrl) {
|
||||
gptimer_pwm_enable(ir_encode->pwm_tid);
|
||||
ir_encode->pwm_high_ctrl = 0;
|
||||
ir_encode->high_level_count--;
|
||||
} else if (ir_encode->high_level_count) {
|
||||
ir_encode->high_level_count--;
|
||||
} else if (ir_encode->pwm_low_ctrl) {
|
||||
gptimer_pwm_disable(ir_encode->pwm_tid);
|
||||
ir_encode->pwm_low_ctrl = 0;
|
||||
ir_encode->low_level_count--;
|
||||
} else if (ir_encode->low_level_count) {
|
||||
ir_encode->low_level_count--;
|
||||
}
|
||||
|
||||
if (ir_encode->low_level_count) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_encode_tx_bit(u32 bit_state)
|
||||
{
|
||||
switch (bit_state) {
|
||||
case HEAD_BIT:
|
||||
ir_encode->high_level_count = IR_NEC_HEAD_H;
|
||||
ir_encode->low_level_count = IR_NEC_HEAD_L;
|
||||
break;
|
||||
case DATA_BIT0:
|
||||
ir_encode->high_level_count = IR_NEC_BIT_0_H;
|
||||
ir_encode->low_level_count = IR_NEC_BIT_0_L;
|
||||
break;
|
||||
case DATA_BIT1:
|
||||
ir_encode->high_level_count = IR_NEC_BIT_1_H;
|
||||
ir_encode->low_level_count = IR_NEC_BIT_1_L;
|
||||
break;
|
||||
case END_BIT:
|
||||
ir_encode->high_level_count = IR_NEC_END_H;
|
||||
if (ir_encode->repeat_en) {
|
||||
ir_encode->low_level_count = IR_NEC_END_REPEAT_L;
|
||||
} else {
|
||||
ir_encode->low_level_count = IR_NEC_END_L;
|
||||
}
|
||||
break;
|
||||
case REPEAT_BIT:
|
||||
ir_encode->high_level_count = IR_NEC_REPEAT_H;
|
||||
ir_encode->low_level_count = IR_NEC_REPEAT_L;
|
||||
break;
|
||||
case REPEAT_END_BIT:
|
||||
ir_encode->high_level_count = IR_NEC_REPEAT_END_H;
|
||||
ir_encode->low_level_count = IR_NEC_REPEAT_END_L;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
ir_encode->pwm_high_ctrl = 1;
|
||||
ir_encode->pwm_low_ctrl = 1;
|
||||
}
|
||||
|
||||
static void ir_encode_irq(u32 tid, void *arg)
|
||||
{
|
||||
u32 bit_state_change = ir_pwm_ctrl();
|
||||
//检查当前bit是否发送完成,切换下一个状态
|
||||
if (bit_state_change == 0) {
|
||||
return;
|
||||
}
|
||||
switch (ir_encode->state) {
|
||||
case IR_IDLE:
|
||||
ir_encode->state = IR_HEAD;
|
||||
break;
|
||||
case IR_HEAD:
|
||||
ir_encode_tx_bit(HEAD_BIT);
|
||||
ir_encode->state = IR_DATA;
|
||||
ir_encode->bit_count = 0;
|
||||
break;
|
||||
case IR_DATA:
|
||||
u32 bit_level = ir_encode->ir_data & BIT(0);
|
||||
ir_encode_tx_bit(bit_level);
|
||||
ir_encode->ir_data >>= 1;
|
||||
ir_encode->bit_count++;
|
||||
if (ir_encode->bit_count == 32) {
|
||||
ir_encode->state = IR_END;
|
||||
}
|
||||
break;
|
||||
case IR_END:
|
||||
ir_encode_tx_bit(END_BIT);
|
||||
ir_encode->state = IR_REPEAT;
|
||||
break;
|
||||
case IR_REPEAT:
|
||||
if (ir_encode->repeat_en) {
|
||||
ir_encode_tx_bit(REPEAT_BIT);
|
||||
ir_encode->state = IR_REPEAT_END;
|
||||
} else {
|
||||
gptimer_pause(ir_encode->timer_tid);
|
||||
ir_encode->state = IR_IDLE;
|
||||
}
|
||||
break;
|
||||
case IR_REPEAT_END:
|
||||
ir_encode_tx_bit(REPEAT_END_BIT);
|
||||
ir_encode->state = IR_REPEAT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
void ir_encoder_init(u32 gpio, u32 freq, u32 duty)
|
||||
{
|
||||
log_info("func:%s(), line:%d\n", __func__, __LINE__);
|
||||
ir_encoder_malloc();
|
||||
|
||||
const struct gptimer_config pwm_config = {
|
||||
.pwm.freq = freq, //设置频率
|
||||
.pwm.port = (gpio / IO_GROUP_NUM), //设置输出IO
|
||||
.pwm.pin = BIT(gpio % IO_GROUP_NUM), //设置输出IO
|
||||
.pwm.duty = duty, //设置占空比
|
||||
.mode = GPTIMER_MODE_PWM, //设置工作模式
|
||||
};
|
||||
#ifdef TCFG_IR_ENCODER_TIMER_TID
|
||||
ir_encode->pwm_tid = (u8)gptimer_init(TCFG_IR_ENCODER_TIMER_TID, &pwm_config); //用户配置固定timer
|
||||
#else
|
||||
ir_encode->pwm_tid = (u8)gptimer_init(TIMERx, &pwm_config); //内部分配空闲timer
|
||||
#endif
|
||||
log_info("pwm_config tid = %d\n", ir_encode->pwm_tid);
|
||||
gpio_set_mode(IO_PORT_SPILT(gpio), PORT_OUTPUT_LOW);
|
||||
gptimer_start(ir_encode->pwm_tid);
|
||||
gptimer_pwm_disable(ir_encode->pwm_tid);
|
||||
|
||||
const struct gptimer_config timer_config = {
|
||||
.timer.period_us = IR_NEC_PULSE_UNIT, //设置定时周期
|
||||
.irq_cb = ir_encode_irq, //设置中断回调函数
|
||||
.irq_priority = 3, //设置中断优先级
|
||||
.mode = GPTIMER_MODE_TIMER, //设置工作模式
|
||||
};
|
||||
#ifdef TCFG_IR_ENCODER_PWM_TID
|
||||
ir_encode->timer_tid = (u8)gptimer_init(TCFG_IR_ENCODER_PWM_TID, &timer_config); //用户配置固定timer
|
||||
#else
|
||||
ir_encode->timer_tid = (u8)gptimer_init(TIMERx, &timer_config); //内部分配空闲timer
|
||||
#endif
|
||||
log_info("timer_config tid = %d\n", ir_encode->timer_tid);
|
||||
}
|
||||
|
||||
void ir_encoder_deinit()
|
||||
{
|
||||
log_info("func:%s(), line:%d\n", __func__, __LINE__);
|
||||
gptimer_deinit(ir_encode->pwm_tid);
|
||||
gptimer_deinit(ir_encode->timer_tid);
|
||||
ir_encode->state = IR_IDLE;
|
||||
ir_encoder_free();
|
||||
}
|
||||
u32 ir_encoder_tx(u8 ir_addr, u8 ir_cmd, u8 repeat_en)
|
||||
{
|
||||
if (ir_encode->state != IR_IDLE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
u32 cmd_not = (~ir_cmd & 0xFF) << 24;
|
||||
u32 addr_not = (~ir_addr & 0xFF) << 8;
|
||||
|
||||
ir_encode->ir_data = cmd_not | (ir_cmd << 16) | addr_not | ir_addr;
|
||||
|
||||
ir_encode->repeat_en = repeat_en;
|
||||
log_info("ir_data 0x%08x repeat_en : %d\n", ir_encode->ir_data, ir_encode->repeat_en);
|
||||
|
||||
gptimer_start(ir_encode->timer_tid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ir_encoder_repeat_stop()
|
||||
{
|
||||
ir_encode->repeat_en = 0;
|
||||
}
|
||||
|
||||
static u8 ir_encoder_status_get()
|
||||
{
|
||||
if (ir_encode->state == IR_IDLE) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
REGISTER_LP_TARGET(ir_encoder_lp_target) = {
|
||||
.name = "ir_encoder",
|
||||
.is_idle = ir_encoder_status_get,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
#include "cpu.h"
|
||||
#include "rdec.h"
|
||||
#include "clock.h"
|
||||
#include "gpio.h"
|
||||
|
||||
const static u8 rdec_index_table[] = {IRQ_RDECx_IDX_LIST};
|
||||
|
||||
static void (*rdec_cb_table[RDEC_MAX_NUM])(u32 tid);
|
||||
|
||||
/* AT(.gptimer.text.cache.L1) */
|
||||
___interrupt
|
||||
static void rdec0_irq()
|
||||
{
|
||||
/* RDEC0->CON |= BIT(RDEC_CPND); */
|
||||
if (rdec_cb_table[0]) {
|
||||
rdec_cb_table[0](0);
|
||||
}
|
||||
}
|
||||
|
||||
static void (* const rdecx_irq_table[])(void) = {
|
||||
rdec0_irq,
|
||||
};
|
||||
|
||||
_INLINE_ static RDEC *rdec_id2rdec(u32 id)
|
||||
{
|
||||
ASSERT(id < RDEC_MAX_NUM, "func:%s(),line:%d, rdecx max num %d", __func__, __LINE__, RDEC_MAX_NUM);
|
||||
return (RDEC_REG_BASE_ADDR + id * RDEC_REG_OFFSET);
|
||||
}
|
||||
|
||||
u32 rdec_init(const struct rdec_config *cfg)
|
||||
{
|
||||
u32 id = cfg->rdec_x;
|
||||
ASSERT(id < RDEC_MAX_NUM, "func:%s(),line:%d, rdecx max num %d", __func__, __LINE__, RDEC_MAX_NUM);
|
||||
|
||||
u32 con = 0;
|
||||
u32 smp = 0;
|
||||
u32 rdec_spnd = clk_get("lsb") / RDEC_FREQ / 16; //计算采样频率
|
||||
SFR(con, RDEC_SPND, 16, rdec_spnd); //设置采样频率
|
||||
|
||||
if (cfg->irq_cb) {
|
||||
rdec_cb_table[id] = cfg->irq_cb;
|
||||
request_irq(rdec_index_table[id], cfg->irq_priority, rdecx_irq_table[id], 0);
|
||||
}
|
||||
if (cfg->work_mode == RDEC_WORK_AUTO) {
|
||||
con &= ~BIT(RDEC_INT_MODE);
|
||||
unrequest_irq(rdec_index_table[id]); //防止意外注册了中断
|
||||
} else if (cfg->work_mode == RDEC_WORK_TIMER) {
|
||||
con |= BIT(RDEC_INT_MODE);
|
||||
smp = RDEC_TIME * RDEC_FREQ / 1000000 - 1; //T = (smp+1)/sr_clk
|
||||
} else if (cfg->work_mode == RDEC_WORK_INTR) {
|
||||
con &= ~BIT(RDEC_INT_MODE);
|
||||
}
|
||||
|
||||
SFR(con, RDEC_MODE, 2, cfg->phase_mode); //设置phase模式
|
||||
con &= ~BIT(RDEC_POL); //设置极性翻转
|
||||
con &= ~BIT(RDEC_EN); //初始化默认关闭
|
||||
|
||||
gpio_set_function(IO_PORT_SPILT(cfg->rdec_a), PORT_FUNC_RDEC0_PORTA + 2 * id);
|
||||
gpio_set_function(IO_PORT_SPILT(cfg->rdec_b), PORT_FUNC_RDEC0_PORTB + 2 * id);
|
||||
|
||||
|
||||
RDEC *RDECx = rdec_id2rdec(id);
|
||||
RDECx->SMP = 0;
|
||||
RDECx->CON = BIT(RDEC_CPND);
|
||||
RDECx->SMP = smp;
|
||||
RDECx->CON = con;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 rdec_start(u32 id)
|
||||
{
|
||||
RDEC *RDECx = rdec_id2rdec(id);
|
||||
RDECx->CON |= BIT(RDEC_EN);
|
||||
return 0;
|
||||
}
|
||||
u32 rdec_pause(u32 id)
|
||||
{
|
||||
RDEC *RDECx = rdec_id2rdec(id);
|
||||
RDECx->CON &= ~BIT(RDEC_EN);
|
||||
return 0;
|
||||
}
|
||||
u32 rdec_resume(u32 id)
|
||||
{
|
||||
RDEC *RDECx = rdec_id2rdec(id);
|
||||
RDECx->CON |= BIT(RDEC_EN);
|
||||
return 0;
|
||||
}
|
||||
int rdec_get_value(u32 id)
|
||||
{
|
||||
s8 data = 0;
|
||||
RDEC *RDECx = rdec_id2rdec(id);
|
||||
if (RDECx->CON & BIT(RDEC_PND)) {
|
||||
RDECx->CON |= BIT(RDEC_CPND);
|
||||
asm("csync");
|
||||
data = RDECx->DAT;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
void rdec_dump()
|
||||
{
|
||||
for (u8 id = RDEC_0; id < RDEC_MAX_NUM; id++) {
|
||||
RDEC *RDECx = rdec_id2rdec(id);
|
||||
printf("RDEC%d->CON:0x%x\n", id, RDECx->CON);
|
||||
printf("RDEC%d->SMP:0x%x\n", id, RDECx->SMP);
|
||||
}
|
||||
}
|
||||
|
||||
struct _rdec_reg {
|
||||
u32 con;
|
||||
u32 smp;
|
||||
};
|
||||
|
||||
static struct _rdec_reg rdec_reg[RDEC_MAX_NUM] AT_VOLATILE_RAM_BSS_LOWPOWER;
|
||||
static u8 rdec_enter_deepsleep(void)
|
||||
{
|
||||
for (u32 i = 0; i < RDEC_MAX_NUM; i++) {
|
||||
RDEC *RDECx = (RDEC *)rdec_id2rdec(i);
|
||||
if (RDECx->CON == 0) {
|
||||
continue;
|
||||
}
|
||||
rdec_reg[i].con = RDECx->CON;
|
||||
rdec_reg[i].smp = RDECx->SMP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
AT_VOLATILE_CACHE_CODE_LOWPOWER
|
||||
static u8 rdec_exit_deepsleep(void)
|
||||
{
|
||||
for (u32 i = 0; i < RDEC_MAX_NUM; i++) {
|
||||
RDEC *RDECx = (RDEC *)(RDEC_REG_BASE_ADDR + i * RDEC_REG_OFFSET);
|
||||
if (rdec_reg[i].con == 0) {
|
||||
continue;
|
||||
}
|
||||
RDECx->CON = rdec_reg[i].con;
|
||||
RDECx->SMP = rdec_reg[i].smp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSLEEP_TARGET_REGISTER(rdec) = {
|
||||
.name = "rdec",
|
||||
.enter = rdec_enter_deepsleep,
|
||||
.exit = rdec_exit_deepsleep,
|
||||
};
|
||||
@@ -0,0 +1,271 @@
|
||||
#include "rdec_soft.h"
|
||||
#include "spinlock.h"
|
||||
#include "gpio.h"
|
||||
#include "gptimer.h"
|
||||
#include "clock.h"
|
||||
|
||||
#define LOG_TAG_CONST PERI
|
||||
#define LOG_TAG "[rdec_soft]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef NO_CONFIG_PORT
|
||||
#define NO_CONFIG_PORT -1
|
||||
#endif
|
||||
|
||||
struct rdec_soft_info {
|
||||
struct rdec_soft_config cfg;
|
||||
s8 cnt; //编码器计数值,带方向
|
||||
s8 cnt_last; //编码器计数值,带方向
|
||||
u8 phase_level; //AB相电平
|
||||
//bit7,bit6:无效信息
|
||||
//bit5,bit4:上上次读取到的AB相电平
|
||||
//bit3,bit2:上次读取到的AB相电平
|
||||
//bit1,bit0:最近一次读取到的AB相电平
|
||||
s8 dir; //旋转方向,用户不需要关注
|
||||
}; //16Byte
|
||||
|
||||
#define RDEC_SOFT_MALLOC_ENABLE 0
|
||||
#if RDEC_SOFT_MALLOC_ENABLE
|
||||
#include "malloc.h"
|
||||
#else
|
||||
static struct rdec_soft_info _rs_info[RDEC_MAX_NUM];
|
||||
#endif
|
||||
static struct rdec_soft_info *g_rs_info[RDEC_MAX_NUM];
|
||||
static u32 rdec_soft_malloc()
|
||||
{
|
||||
u8 id = RDEC_SOFT_ERR_INIT_FAIL;
|
||||
for (u8 i = 0; i < RDEC_MAX_NUM; i++) { //分配g_rs_info id号
|
||||
if (g_rs_info[i] == NULL) {
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(id != RDEC_SOFT_ERR_INIT_FAIL, "func:%s, line:%d, rdec_soft malloc fail. need increase RDEC_MAX_NUM\n", __func__, __LINE__);
|
||||
|
||||
#if RDEC_SOFT_MALLOC_ENABLE
|
||||
g_rs_info[id] = (struct rdec_soft_config *)zalloc(sizeof(struct rdec_soft_config));
|
||||
#else
|
||||
g_rs_info[id] = &_rs_info[id];
|
||||
ASSERT(g_rs_info[id] != NULL, "func:%s(), line:%d, id:%d fail!\n", __func__, __LINE__, id);
|
||||
memset(g_rs_info[id], 0, sizeof(struct rdec_soft_config));
|
||||
#endif
|
||||
log_info("func:%s(),line:%d, rdec_soft:%d init success\n", __func__, __LINE__, id);
|
||||
return id;
|
||||
}
|
||||
static u32 rdec_soft_free(const u32 id)
|
||||
{
|
||||
ASSERT(g_rs_info[id], "%s()\n", __func__);
|
||||
#if RDEC_SOFT_MALLOC_ENABLE
|
||||
free(g_rs_info[id]);
|
||||
#else
|
||||
g_rs_info[id] = NULL;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rdec_soft_cfg_dump(struct rdec_soft_info *cfg)
|
||||
{
|
||||
printf("func:%s, line:%d\n", __func__, __LINE__);
|
||||
printf("cfg->rdec.rdec_a: 0x%x\n", cfg->cfg.rdec_a);
|
||||
printf("cfg->rdec.rdec_b: 0x%x\n", cfg->cfg.rdec_b);
|
||||
printf("cfg->rdec.mode: %d\n", cfg->cfg.mode);
|
||||
printf("cfg->cfg.filter_us: %dus\n", cfg->cfg.filter_us);
|
||||
}
|
||||
|
||||
static void phase_direction_check(struct rdec_soft_info *g_rs_info)
|
||||
{
|
||||
s8 direction = 0;
|
||||
u8 data = g_rs_info->phase_level & 0b111111;
|
||||
switch (data) {
|
||||
case 0b001011:
|
||||
case 0b110100:
|
||||
direction = 1;
|
||||
g_rs_info->dir = direction;
|
||||
break;
|
||||
case 0b000111:
|
||||
case 0b111000:
|
||||
direction = -1;
|
||||
g_rs_info->dir = direction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
g_rs_info->cnt += direction;
|
||||
if (direction != 0) {
|
||||
if ((data & 0b11) == 0b11) {
|
||||
gptimer_set_work_mode(g_rs_info->cfg.tid, GPTIMER_MODE_CAPTURE_EDGE_FALL);
|
||||
} else if ((data & 0b11) == 0b00) {
|
||||
gptimer_set_work_mode(g_rs_info->cfg.tid, GPTIMER_MODE_CAPTURE_EDGE_RISE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
static void phase_level_check(struct rdec_soft_info *g_rs_info, u8 stage)
|
||||
{
|
||||
const u8 phase_level_last = g_rs_info->phase_level & 0b11;
|
||||
u8 phase_a_level;
|
||||
if (stage) {
|
||||
phase_a_level = phase_level_last & BIT(1);
|
||||
} else {
|
||||
phase_a_level = gpio_read(g_rs_info->cfg.rdec_a) << 1;
|
||||
}
|
||||
u8 phase_b_level = gpio_read(g_rs_info->cfg.rdec_b);
|
||||
u8 phase_level_cur = phase_a_level | phase_b_level;
|
||||
if (phase_level_cur == phase_level_last) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_rs_info->phase_level <<= 2;
|
||||
g_rs_info->phase_level |= phase_level_cur;
|
||||
|
||||
if (phase_a_level != phase_b_level << 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
phase_direction_check(g_rs_info);
|
||||
switch (g_rs_info->cfg.mode) {
|
||||
case RDEC_SOFT_PHASE_1:
|
||||
break;
|
||||
|
||||
case RDEC_SOFT_PHASE_2:
|
||||
//
|
||||
if (phase_level_cur == 0b11) {
|
||||
if (g_rs_info->cnt % 2) {
|
||||
g_rs_info->cnt -= g_rs_info->dir;
|
||||
} else {
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void rdec_soft_irq(u32 tid, void *private_data)
|
||||
{
|
||||
ASSERT(private_data != NULL, "func:%s, line:%d, private_data is NULL.\n", __func__, __LINE__);
|
||||
struct rdec_soft_info *rs_info = (struct rdec_soft_info *)private_data;
|
||||
u8 timer_mode = gptimer_get_work_mode(tid);
|
||||
switch (timer_mode) {
|
||||
case GPTIMER_MODE_CAPTURE_EDGE_RISE:
|
||||
case GPTIMER_MODE_CAPTURE_EDGE_FALL:
|
||||
case GPTIMER_MODE_CAPTURE_EDGE_ANYEDGE:
|
||||
phase_level_check(rs_info, 1);
|
||||
gptimer_set_timer_period(tid, rs_info->cfg.filter_us);
|
||||
gptimer_set_work_mode(tid, GPTIMER_MODE_TIMER);
|
||||
break;
|
||||
case GPTIMER_MODE_TIMER:
|
||||
phase_level_check(rs_info, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u32 rdec_soft_init(const struct rdec_soft_config *cfg)
|
||||
{
|
||||
log_info("func:%s, line:%d\n", __func__, __LINE__);
|
||||
|
||||
const struct gptimer_config rdec_capture_config = {
|
||||
.capture.filter = 0,
|
||||
.capture.port = (cfg->rdec_a / IO_GROUP_NUM),
|
||||
.capture.pin = BIT(cfg->rdec_a % IO_GROUP_NUM),
|
||||
.irq_cb = rdec_soft_irq,
|
||||
.irq_priority = 1,
|
||||
.mode = GPTIMER_MODE_CAPTURE_EDGE_FALL,
|
||||
.private_data = NULL,
|
||||
};
|
||||
u32 tid = gptimer_init(cfg->tid, &rdec_capture_config);
|
||||
log_info("rdec_soft capture_tid = %d\n", tid);
|
||||
|
||||
u8 id = rdec_soft_malloc();
|
||||
gptimer_set_private_data(tid, g_rs_info[id]);
|
||||
memcpy(&g_rs_info[id]->cfg, cfg, sizeof(struct rdec_soft_config));
|
||||
rdec_soft_cfg_dump(g_rs_info[id]);
|
||||
|
||||
if (cfg->rdec_a != NO_CONFIG_PORT) {
|
||||
if (cfg->mode == RDEC_SOFT_PHASE_2_ADC) {
|
||||
gpio_set_mode(IO_PORT_SPILT(cfg->rdec_a), PORT_INPUT_FLOATING);
|
||||
} else {
|
||||
gpio_set_mode(IO_PORT_SPILT(cfg->rdec_a), PORT_INPUT_PULLUP_10K);
|
||||
}
|
||||
}
|
||||
if (cfg->rdec_b != NO_CONFIG_PORT) {
|
||||
gpio_set_mode(IO_PORT_SPILT(cfg->rdec_b), PORT_INPUT_PULLUP_10K);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void rdec_soft_deinit(u32 id)
|
||||
{
|
||||
log_info("func:%s, line:%d\n", __func__, __LINE__);
|
||||
ASSERT(g_rs_info[id] != NULL, "func:%s, line:%d, rx_info[%d] is NULL.\n", __func__, __LINE__, id);
|
||||
gptimer_deinit(g_rs_info[id]->cfg.tid);
|
||||
gpio_set_mode(IO_PORT_SPILT(g_rs_info[id]->cfg.rdec_a), PORT_HIGHZ);
|
||||
gpio_set_mode(IO_PORT_SPILT(g_rs_info[id]->cfg.rdec_b), PORT_HIGHZ);
|
||||
memset(g_rs_info[id], 0, sizeof(struct rdec_soft_info));
|
||||
rdec_soft_free(id);
|
||||
}
|
||||
|
||||
void rdec_soft_start(u32 id)
|
||||
{
|
||||
log_info("func:%s, line:%d\n", __func__, __LINE__);
|
||||
ASSERT(g_rs_info[id] != NULL, "func:%s, line:%d, rx_info[%d] is NULL.\n", __func__, __LINE__, id);
|
||||
u8 mode = g_rs_info[id]->cfg.mode;
|
||||
if ((mode == RDEC_SOFT_PHASE_1) || (mode == RDEC_SOFT_PHASE_2)) {
|
||||
phase_level_check(g_rs_info[id], 0);
|
||||
if (gpio_read(g_rs_info[id]->cfg.rdec_a) == 1) {
|
||||
gptimer_set_work_mode(g_rs_info[id]->cfg.tid, GPTIMER_MODE_CAPTURE_EDGE_FALL);
|
||||
} else {
|
||||
gptimer_set_work_mode(g_rs_info[id]->cfg.tid, GPTIMER_MODE_CAPTURE_EDGE_RISE);
|
||||
}
|
||||
} else if (mode == RDEC_SOFT_PHASE_2_ADC) {
|
||||
gptimer_set_work_mode(g_rs_info[id]->cfg.tid, GPTIMER_MODE_CAPTURE_EDGE_FALL);
|
||||
} else {
|
||||
log_info("rdec_cfg_mode error!\n");
|
||||
}
|
||||
}
|
||||
void rdec_soft_pause(u32 id)
|
||||
{
|
||||
log_info("func:%s, line:%d\n", __func__, __LINE__);
|
||||
ASSERT(g_rs_info[id] != NULL, "func:%s, line:%d, rx_info[%d] is NULL.\n", __func__, __LINE__, id);
|
||||
gptimer_pause(g_rs_info[id]->cfg.tid);
|
||||
}
|
||||
|
||||
void rdec_soft_resume(u32 id)
|
||||
{
|
||||
rdec_soft_start(id);
|
||||
}
|
||||
|
||||
int rdec_soft_get_value(u32 id)
|
||||
{
|
||||
ASSERT(g_rs_info[id] != NULL, "func:%s, line:%d, rx_info[%d] is NULL.\n", __func__, __LINE__, id);
|
||||
log_debug("cnt:%d, cnt_last:%d\n", g_rs_info[id]->cnt, g_rs_info[id]->cnt_last);
|
||||
s16 cnt_diff = ((s16)g_rs_info[id]->cnt - (s16)g_rs_info[id]->cnt_last);
|
||||
s8 cnt_last = g_rs_info[id]->cnt_last;
|
||||
g_rs_info[id]->cnt_last = g_rs_info[id]->cnt;
|
||||
if (cnt_diff > 127) {
|
||||
cnt_diff = cnt_diff - 0x100;
|
||||
} else if (cnt_diff < -128) {
|
||||
cnt_diff = cnt_diff + 0x100;
|
||||
}
|
||||
log_debug("cnt_diff:%d\n", cnt_diff);
|
||||
if (g_rs_info[id]->cfg.mode == RDEC_SOFT_PHASE_2) {
|
||||
if (cnt_diff % 2) {
|
||||
g_rs_info[id]->cnt_last = cnt_last;
|
||||
cnt_diff = 0;
|
||||
} else {
|
||||
cnt_diff /= 2;
|
||||
}
|
||||
}
|
||||
return (int)cnt_diff;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user