KT24-1110_65E-HA-651B/cpu/br25/iic_slave_test.c

316 lines
10 KiB
C
Raw Normal View History

2024-11-10 10:44:17 +00:00
#include "system/includes.h"
#include "media/includes.h"
//#include "device/iic.h"
#include "asm/iic_hw.h"
#include "asm/iic_soft.h"
#if 0
/*
[[[ README ]]]
1. iic从机需要赋值hw_iic_cfg.role = IIC_SLAVErole没有赋值或赋值成
IIC_MASTER
2. iic从机的demo使用中断-while(!iic_pnd)
CPU浪费及响应不及时IIC没有DMA1 byte就会触发1次中断IIC主机
1delay一段时间IIC从机响应中断iic stop产生的
end中断被用于计算接收字节数及复位状态机end中断的使能及处理IIC可能
end中断end中断的处理必须用start-end包住
3. demo的接收/使double buffer/
4. IIC从机收到IIC_S_RADDR后需要尽快准备需要发送的数据
IIC字节时钟以请求数据
5. IIC主机的TX的STOP到下个RX的START需要delay一段时间
6.
*/
#define IIC_S_RADDR 0x61
#define IIC_S_WADDR 0x60
#define IIC_S_DEV 0
#define IIC_S_TXBUF_SIZE 128
#define IIC_S_RXBUF_SIZE 128
enum {
IIC_S_MSG_TX,
IIC_S_MSG_RX,
};
struct iic_s_tx_statemachine {
u8 *buf[2];
u32 b_size;
bool toggle;
u32 cur_cnt;
u32 tx_cnt;
};
struct iic_s_rx_statemachine {
u8 *buf[2];
u32 b_size;
bool toggle;
u32 cur_cnt;
u32 rx_cnt;
};
struct iic_slave {
enum {IIC_S_TX, IIC_S_RX} dir;
struct iic_s_tx_statemachine tx;
struct iic_s_rx_statemachine rx;
u8 bus_occupy;
};
static struct iic_slave iic_s;
static u8 iic_s_txbuf[2][IIC_S_TXBUF_SIZE];
static u8 iic_s_rxbuf[2][IIC_S_RXBUF_SIZE];
SET_INTERRUPT
static void iic_slave_isr()
{
u8 is_addr = 0;
u8 byte;
if (hw_iic_get_pnd(IIC_S_DEV)) {
hw_iic_clr_pnd(IIC_S_DEV);
putchar('a');
if (iic_s.dir == IIC_S_RX) {
byte = hw_iic_slave_rx_byte(IIC_S_DEV, &is_addr); //判断是否为地址
if (is_addr) {
iic_s.rx.cur_cnt = 0;
iic_s.rx.rx_cnt = 0;
iic_s.tx.cur_cnt = 0;
iic_s.tx.tx_cnt = 0;
if (byte == IIC_S_WADDR) {
putchar('b');
hw_iic_slave_rx_prepare(IIC_S_DEV, 1); //触发下1 byte接收并使能recv ack
iic_s.bus_occupy = 1;
} else if (byte == IIC_S_RADDR) {
putchar('c');
iic_s.dir = IIC_S_TX;
os_taskq_post_msg("iic_slave", 1, IIC_S_MSG_TX);
iic_s.bus_occupy = 1; //包住start-stop避免处理意外的stop处理
}
} else {
putchar('d');
if (iic_s.rx.cur_cnt < iic_s.rx.b_size) {
iic_s.rx.buf[iic_s.rx.toggle][iic_s.rx.cur_cnt++] = byte;
}
hw_iic_slave_rx_prepare(IIC_S_DEV, 1); //触发下1 byte接收并使能recv ack
}
} else {
putchar('e');
//如果主机接收ACK或者是最后1 byte主机NACK发送下1 byte否则重发当前byte
if (hw_iic_slave_tx_check_ack(IIC_S_DEV) ||
(iic_s.tx.tx_cnt - iic_s.tx.cur_cnt == 1)) {
iic_s.tx.cur_cnt++;
}
if (iic_s.tx.cur_cnt < iic_s.tx.tx_cnt) {
hw_iic_slave_tx_byte(IIC_S_DEV, iic_s.tx.buf[iic_s.tx.toggle][iic_s.tx.cur_cnt]);
} else {
//如果主机请求字节数比实际IIC发送字节数多则发送0xff防止主机while(!iic_pnd)阻塞卡死
hw_iic_slave_tx_byte(IIC_S_DEV, 0xff);
}
}
}
if (hw_iic_get_end_pnd(IIC_S_DEV)) {
hw_iic_clr_end_pnd(IIC_S_DEV);
putchar('f');
//start-stop包住收到stop时的处理
if (iic_s.bus_occupy) {
iic_s.bus_occupy = 0;
if (iic_s.dir == IIC_S_RX) {
putchar('g');
iic_s.rx.toggle = !iic_s.rx.toggle;
iic_s.rx.rx_cnt = iic_s.rx.cur_cnt;
os_taskq_post_msg("iic_slave", 2, IIC_S_MSG_RX, iic_s.rx.rx_cnt);
} else {
putchar('h');
iic_s.tx.toggle = !iic_s.tx.toggle;
}
iic_s.dir = IIC_S_RX;
iic_s.rx.cur_cnt = 0;
iic_s.tx.cur_cnt = 0;
iic_s.tx.tx_cnt = 0;
hw_iic_slave_rx_prepare(IIC_S_DEV, 0); //触发下1 byte接收并NACK
}
}
}
static void iic_slave_task(void *arg)
{
int res;
int msg[8];
u32 rxlen = 0;
u32 txlen = 0;
u8 *addr;
printf("iic_slave_task run\n");
memset(&iic_s, 0, sizeof(struct iic_slave));
iic_s.dir = IIC_S_RX;
iic_s.rx.buf[0] = iic_s_rxbuf[0];
iic_s.rx.buf[1] = iic_s_rxbuf[1];
iic_s.rx.b_size = IIC_S_RXBUF_SIZE;
iic_s.tx.buf[0] = iic_s_txbuf[0];
iic_s.tx.buf[1] = iic_s_txbuf[1];
iic_s.tx.b_size = IIC_S_TXBUF_SIZE;
hw_iic_init(IIC_S_DEV);
//设置IIC从机地址并且使能地址包自动ACK
hw_iic_slave_set_addr(IIC_S_DEV, IIC_S_WADDR, 1);
//注册中断isr
request_irq(IRQ_IIC_IDX, 3, iic_slave_isr, 0);
//使能byte传输中断
hw_iic_set_ie(IIC_S_DEV, 1);
//使能stop中断
hw_iic_set_end_ie(IIC_S_DEV, 1);
//请求接收禁止ACK避免与地址包自动ACK冲突。bit ACK需要在接收数据前设置
//闭ACK并打开地址包自动ACK是为了挂多个IIC从机时本IIC从机不会ACK其他IIC设备
//地址造成多从机失效。地址包自动ACK只有当从机收到设置的地址才会ACK否则
//NACK
hw_iic_slave_rx_prepare(IIC_S_DEV, 0);
__asm__ volatile("%0 = icfg" : "=r"(res));
printf("icfg = %08x\n", res);
while (1) {
res = os_taskq_pend("taskq", msg, 8);
switch (res) {
case OS_TASKQ:
switch (msg[0]) {
case Q_MSG:
switch (msg[1]) {
case IIC_S_MSG_RX:
puts(">>>>>> iic_s rx msg\n");
rxlen = msg[2];
addr = iic_s.rx.buf[!iic_s.rx.toggle];
printf("rx len: %d\n", rxlen);
//put_buf(addr, rxlen);
for (int i = 0; i < rxlen; i++) {
putchar(*(addr + i));
putchar(0x20);
if (i % 16 == 15) {
putchar('\n');
}
}
break;
case IIC_S_MSG_TX:
puts(">>>>>> iic_s tx msg\n");
txlen = rxlen;
memcpy(iic_s.tx.buf[!iic_s.tx.toggle], iic_s.rx.buf[!iic_s.rx.toggle], txlen);
iic_s.tx.tx_cnt = txlen;
hw_iic_slave_tx_byte(IIC_S_WADDR, iic_s.tx.buf[!iic_s.tx.toggle][0]);
iic_s.tx.toggle = !iic_s.tx.toggle;
printf("tx req len: %d\n", txlen);
break;
}
break;
}
break;
}
}
}
void iic_demo_slave_main()
{
printf("%s() %d\n", __func__, __LINE__);
os_task_create(iic_slave_task, NULL, 30, 1024, 64, "iic_slave");
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~ iic host below ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#define IIC_H_DEV 0
#define IIC_H_TXBUF_SIZE 128
#define IIC_H_RXBUF_SIZE 128
#define IIC_H_DELAY 500
#define iic_h_check_ack(ack, pCnt) \
if (!(ack)) { \
printf("nack %d\n", __LINE__); \
if (*(pCnt) > 0 && --(*(pCnt))) { \
continue; \
} else { \
break; \
} \
}
static u8 iic_h_txbuf[IIC_H_TXBUF_SIZE];
static u8 iic_h_rxbuf[IIC_H_RXBUF_SIZE];
void iic_demo_host_main()
{
int i;
int ret;
u32 retry;
u8 byte;
printf("%s() %d\n", __func__, __LINE__);
hw_iic_init(IIC_H_DEV);
for (i = 0; i < IIC_H_TXBUF_SIZE; i++) {
iic_h_txbuf[i] = 'A' + i % 26;
}
for (u8 times = 0; times < 3; times++) { //测试次数
retry = 10;
do {
hw_iic_start(IIC_H_DEV);
putchar('a');
ret = hw_iic_tx_byte(IIC_H_DEV, IIC_S_WADDR);
putchar('b');
iic_h_check_ack(ret, &retry);
delay(IIC_H_DELAY);
i = 0;
while (i < IIC_H_TXBUF_SIZE) {
ret = hw_iic_tx_byte(IIC_H_DEV, iic_h_txbuf[i]);
putchar('c');
iic_h_check_ack(ret, &retry);
delay(IIC_H_DELAY);
i++;
}
break;
} while (1);
hw_iic_stop(IIC_H_DEV);
delay(IIC_H_DELAY); //stop后需要delay一段时间后再start
retry = 10;
do {
hw_iic_start(IIC_H_DEV);
putchar('d');
ret = hw_iic_tx_byte(IIC_H_DEV, IIC_S_RADDR);
putchar('e');
iic_h_check_ack(ret, &retry);
delay(IIC_H_DELAY);
i = 0;
while (i < IIC_H_RXBUF_SIZE - 1) {
iic_h_rxbuf[i] = hw_iic_rx_byte(IIC_H_DEV, 1);
putchar('f');
delay(IIC_H_DELAY);
i++;
}
iic_h_rxbuf[i] = hw_iic_rx_byte(IIC_H_DEV, 0); //IIC主机接收最后1 byte NACK
putchar('g');
delay(IIC_H_DELAY);
break;
} while (1);
hw_iic_stop(IIC_H_DEV); //stop后需要delay一段时间后再start
delay(IIC_H_DELAY);
putchar('\n');
ret = 0;
for (i = 0; i < IIC_H_RXBUF_SIZE; i++) {
putchar(iic_h_rxbuf[i]);
putchar(0x20);
if (i % 16 == 15) {
putchar('\n');
}
if (iic_h_txbuf[i] != iic_h_rxbuf[i]) {
ret = 1;
}
}
if (!ret) {
puts("iic slave test pass\n");
} else {
puts("iic slave test fail\n");
}
}
}
#endif