This commit is contained in:
huxi
2025-12-03 11:12:34 +08:00
parent c23ae4f24c
commit bc195654bf
8163 changed files with 3799544 additions and 92 deletions
+495
View File
@@ -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
}
+353
View File
@@ -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;
}
+216
View File
@@ -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));
}
+281
View File
@@ -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,
};
+146
View File
@@ -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,
};
+271
View File
@@ -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;
}