You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
12 KiB
433 lines
12 KiB
#include "driver/slc_register.h"
|
|
#include "driver/sdio_slv.h"
|
|
#include "ets_sys.h"
|
|
#include "osapi.h"
|
|
#include "os_type.h"
|
|
//#include "gpio.h"
|
|
#include "user_interface.h"
|
|
#include "mem.h"
|
|
|
|
#define SDIO_TOKEN_SIZE 0//4
|
|
#define RX_BUFFER_SIZE 512
|
|
#define RX_BUFFER_NUM 4
|
|
|
|
#define TX_BUFFER_SIZE 512
|
|
#define SLC_INTEREST_EVENT (SLC_TX_EOF_INT_ENA | SLC_RX_EOF_INT_ENA | SLC_RX_UDF_INT_ENA | SLC_TX_DSCR_ERR_INT_ENA)
|
|
#define TRIG_TOHOST_INT() SET_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0);\
|
|
//CLEAR_PERI_REG_MASK(SLC_INTVEC_TOHOST , BIT0)
|
|
struct sdio_queue
|
|
{
|
|
uint32 blocksize:12;
|
|
uint32 datalen:12;
|
|
uint32 unused:5;
|
|
uint32 sub_sof:1;
|
|
uint32 eof:1;
|
|
uint32 owner:1;
|
|
|
|
uint32 buf_ptr;
|
|
uint32 next_link_ptr;
|
|
};
|
|
|
|
struct sdio_slave_status_element
|
|
{
|
|
uint32 wr_busy:1;
|
|
uint32 rd_empty :1;
|
|
uint32 comm_cnt :3;
|
|
uint32 intr_no :3;
|
|
uint32 rx_length:16;
|
|
uint32 res:8;
|
|
};
|
|
|
|
union sdio_slave_status
|
|
{
|
|
struct sdio_slave_status_element elm_value;
|
|
uint32 word_value;
|
|
};
|
|
|
|
//uint8 rx_buffer[RX_BUFFER_NUM][RX_BUFFER_SIZE],tx_buffer[1024];
|
|
uint8 tx_buffer[TX_BUFFER_SIZE];
|
|
|
|
uint32 data_len = 0;
|
|
|
|
struct sdio_list {
|
|
uint8 buffer[RX_BUFFER_SIZE + SDIO_TOKEN_SIZE];
|
|
uint8* tail;
|
|
struct sdio_list* next;
|
|
};
|
|
|
|
static sdio_recv_data_callback_t sdio_recv_data_callback_ptr = NULL;
|
|
struct sdio_list* pHead_ToSend;
|
|
struct sdio_list* pTail_ToSend;
|
|
struct sdio_list* pHead_Sended;
|
|
struct sdio_list* pTail_Sended;
|
|
|
|
|
|
|
|
os_event_t * sdioQueue;
|
|
struct sdio_queue rx_que,tx_que;
|
|
|
|
static bool has_read = 0;
|
|
|
|
static void sdio_slave_isr(void *para);
|
|
static void tx_buff_handle_done(void);
|
|
static void rx_buff_read_done(void);
|
|
static void tx_buff_write_done(void);
|
|
|
|
static void sdio_try_to_load(void);
|
|
static void sdio_read_done_process(void);
|
|
|
|
void sdio_slave_init(void)
|
|
{
|
|
uint32 regval = 0;
|
|
union sdio_slave_status sdio_sta;
|
|
ETS_SDIO_INTR_DISABLE();
|
|
////reset orginal link
|
|
SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
|
|
CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
|
|
|
|
os_printf("RX&TX link reset!\n");
|
|
|
|
//set sdio mode
|
|
SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
|
|
//clear to host interrupt io signal for preventing from random initial signal.
|
|
WRITE_PERI_REG(SLC_HOST_INTR_CLR, 0xffffffff);
|
|
//enable 2 events to trigger the to host intr io
|
|
SET_PERI_REG_MASK(SLC_HOST_INTR_ENA , SLC_HOST_TOHOST_BIT0_INT_ENA);
|
|
////initialize rx queue information
|
|
|
|
has_read = TRUE;
|
|
pHead_ToSend = NULL;
|
|
|
|
int loop = RX_BUFFER_NUM;
|
|
struct sdio_list* p = NULL;
|
|
while(loop--) {
|
|
if(pHead_Sended == NULL) {
|
|
pHead_Sended = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
|
|
p = pHead_Sended;
|
|
} else {
|
|
p->next = (struct sdio_list*)os_malloc(sizeof(struct sdio_list));
|
|
p = p->next;
|
|
}
|
|
//os_printf("p:0x%08x\r\n",p);
|
|
p->tail = p->buffer + SDIO_TOKEN_SIZE;
|
|
p->next = NULL;
|
|
}
|
|
pTail_Sended = p;
|
|
|
|
rx_que.blocksize = RX_BUFFER_SIZE;
|
|
rx_que.datalen=0;
|
|
rx_que.eof=1;
|
|
rx_que.owner=1;
|
|
rx_que.sub_sof=0;
|
|
rx_que.unused=0;
|
|
rx_que.buf_ptr=(uint32)pHead_Sended->buffer;
|
|
rx_que.next_link_ptr=0;
|
|
|
|
|
|
////initialize tx queue information
|
|
tx_que.blocksize=TX_BUFFER_SIZE;
|
|
tx_que.datalen=0;
|
|
tx_que.eof=0;
|
|
tx_que.owner=1;
|
|
tx_que.sub_sof=0;
|
|
tx_que.unused=0;
|
|
tx_que.buf_ptr=(uint32)tx_buffer;
|
|
tx_que.next_link_ptr=0;
|
|
|
|
///////link tx&rx queue information address to sdio hardware
|
|
CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
|
|
regval= ((uint32)&rx_que);
|
|
SET_PERI_REG_MASK(SLC_RX_LINK, regval&SLC_RXLINK_DESCADDR_MASK);
|
|
CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK);
|
|
regval= ((uint32)&tx_que);
|
|
SET_PERI_REG_MASK(SLC_TX_LINK, regval&SLC_TXLINK_DESCADDR_MASK);
|
|
|
|
#if (SDIO_TOKEN_SIZE == 0)
|
|
SET_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_TOKEN_NO_REPLACE);
|
|
#endif
|
|
|
|
/////config sdio_status reg
|
|
sdio_sta.elm_value.comm_cnt=7;
|
|
sdio_sta.elm_value.intr_no=INIT_STAGE;
|
|
sdio_sta.elm_value.wr_busy=0;
|
|
sdio_sta.elm_value.rd_empty=1;
|
|
sdio_sta.elm_value.rx_length=0;
|
|
sdio_sta.elm_value.res=0;
|
|
SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);
|
|
WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value);
|
|
|
|
|
|
/////attach isr func to sdio interrupt
|
|
ETS_SDIO_INTR_ATTACH(sdio_slave_isr, NULL);
|
|
/////enable sdio operation intr
|
|
WRITE_PERI_REG(SLC_INT_ENA, SLC_INTEREST_EVENT);
|
|
/////clear sdio initial random active intr signal
|
|
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
|
|
/////enable sdio intr in cpu
|
|
ETS_SDIO_INTR_ENABLE();
|
|
}
|
|
|
|
static void sdio_slave_isr(void *para)
|
|
{
|
|
uint32 slc_intr_status,postval;
|
|
static uint8 state =0;
|
|
uint16 rx_len,i;
|
|
uint32* pword;
|
|
union sdio_slave_status sdio_sta;
|
|
|
|
slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
|
|
|
|
if (slc_intr_status == 0)
|
|
{
|
|
/* No interested interrupts pending */
|
|
return;
|
|
}
|
|
//clear all intrs
|
|
WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
|
|
//os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
|
|
//process every intr
|
|
|
|
//TO HOST DONE
|
|
if (slc_intr_status & SLC_RX_EOF_INT_ENA)
|
|
{
|
|
//following code must be called after a data pack has been read
|
|
rx_buff_read_done();
|
|
//TRIG_TOHOST_INT();
|
|
//system_os_post(2, 1, 0);
|
|
sdio_read_done_process();
|
|
}
|
|
|
|
//FROM HOST DONE
|
|
if (slc_intr_status & SLC_TX_EOF_INT_ENA)
|
|
{
|
|
//call the following function after host cpu data transmission finished
|
|
tx_buff_write_done();
|
|
|
|
//system_os_post(USER_TASK_PRIO_1,SDIO_DATA_ERROR,0);
|
|
//os_printf("%d,%s\r\n",tx_que.datalen,tx_que.buf_ptr);
|
|
//at_fake_uart_rx((uint8*)tx_que.buf_ptr,tx_que.datalen);
|
|
if(sdio_recv_data_callback_ptr) {
|
|
sdio_recv_data_callback_ptr((uint8*)tx_que.buf_ptr,tx_que.datalen);
|
|
}
|
|
tx_buff_handle_done();
|
|
TRIG_TOHOST_INT();
|
|
//system_os_post(2, 3, 0);
|
|
}
|
|
|
|
//TO HOST underflow
|
|
if(slc_intr_status & SLC_RX_UDF_INT_ENA)
|
|
{
|
|
}
|
|
|
|
//FROM HOST overflow
|
|
if(slc_intr_status & SLC_TX_DSCR_ERR_INT_ENA)
|
|
{
|
|
}
|
|
|
|
slc_intr_status = READ_PERI_REG(SLC_INT_STATUS);
|
|
if(slc_intr_status)
|
|
{
|
|
WRITE_PERI_REG(SLC_INT_CLR, slc_intr_status);
|
|
os_printf("slc_intr_status:0x%08x\r\n",slc_intr_status);
|
|
}
|
|
|
|
}
|
|
|
|
static void rx_buff_read_done(void)
|
|
{
|
|
union sdio_slave_status sdio_sta;
|
|
/////modify sdio status reg
|
|
sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
|
|
sdio_sta.elm_value.comm_cnt++;
|
|
sdio_sta.elm_value.rd_empty=1;
|
|
sdio_sta.elm_value.rx_length=0;
|
|
sdio_sta.elm_value.intr_no &= (~RX_AVAILIBLE);
|
|
WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
|
|
//os_printf("rx_buff_read_done\r\n");
|
|
}
|
|
|
|
static void tx_buff_write_done(void)
|
|
{
|
|
union sdio_slave_status sdio_sta;
|
|
/////modify sdio status reg
|
|
sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
|
|
sdio_sta.elm_value.comm_cnt++;
|
|
sdio_sta.elm_value.wr_busy=1;
|
|
sdio_sta.elm_value.intr_no &= (~TX_AVAILIBLE);
|
|
WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
|
|
}
|
|
|
|
static void tx_buff_handle_done(void)
|
|
{
|
|
union sdio_slave_status sdio_sta;
|
|
|
|
/////config tx queue information
|
|
tx_que.blocksize=TX_BUFFER_SIZE;
|
|
tx_que.datalen=0;
|
|
tx_que.eof=0;
|
|
tx_que.owner=1;
|
|
|
|
/////modify sdio status reg
|
|
sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
|
|
sdio_sta.elm_value.wr_busy=0;
|
|
sdio_sta.elm_value.intr_no |= TX_AVAILIBLE;
|
|
|
|
SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START); //tx buffer is ready for being written
|
|
WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
|
|
//*******************************************************************//
|
|
|
|
}
|
|
static int32 rx_buff_load_done(uint16 rx_len)
|
|
{
|
|
union sdio_slave_status sdio_sta;
|
|
|
|
if(rx_len == 0) {
|
|
return 0;
|
|
}
|
|
if(rx_len > rx_que.blocksize)
|
|
{
|
|
rx_len = rx_que.blocksize;
|
|
}
|
|
|
|
//os_memcpy(rx_que.buf_ptr,data,rx_len);
|
|
/////config rx queue information
|
|
rx_que.blocksize=RX_BUFFER_SIZE;
|
|
rx_que.datalen=rx_len + SDIO_TOKEN_SIZE;
|
|
rx_que.eof=1;
|
|
rx_que.owner=1;
|
|
|
|
//ETS_SDIO_INTR_DISABLE();
|
|
//available_buffer_amount--;
|
|
|
|
/////modify sdio status reg
|
|
sdio_sta.word_value=READ_PERI_REG(SLC_HOST_CONF_W2);
|
|
sdio_sta.elm_value.rd_empty=0;
|
|
sdio_sta.elm_value.intr_no |= RX_AVAILIBLE;
|
|
sdio_sta.elm_value.rx_length=rx_len;
|
|
|
|
SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START); //rx buffer is ready for being read
|
|
WRITE_PERI_REG(SLC_HOST_CONF_W2, sdio_sta.word_value); //update sdio status register
|
|
//ETS_SDIO_INTR_ENABLE();
|
|
//os_printf("rx_buff_load_done(%d,0x%08x):%s\r\n",rx_len,rx_que.buf_ptr,rx_que.buf_ptr);
|
|
//os_printf("rx_buff_load_done:%d\r\n",rx_len);
|
|
return rx_len;
|
|
}
|
|
|
|
int32 ICACHE_FLASH_ATTR sdio_load_data(const uint8* data,uint32 len)
|
|
{
|
|
int32 data_len = 0;
|
|
|
|
if (pHead_Sended == NULL) {
|
|
os_printf("no buf\r\n");
|
|
return 0;
|
|
}
|
|
int32 left_len = 0;
|
|
|
|
while(len)
|
|
{
|
|
left_len = RX_BUFFER_SIZE + SDIO_TOKEN_SIZE - (uint32)(pHead_Sended->tail - pHead_Sended->buffer);
|
|
if(len < left_len)
|
|
{
|
|
os_memcpy(pHead_Sended->tail,data,len);
|
|
pHead_Sended->tail += len;
|
|
len = 0;
|
|
data_len += len;
|
|
//os_printf(">555:0x%08x,0x%08x\r\n",pHead_Sended->buffer,pHead_Sended->tail);
|
|
}
|
|
else
|
|
{
|
|
os_memcpy(pHead_Sended->tail,data,left_len);
|
|
pHead_Sended->tail += left_len;
|
|
len -= left_len;
|
|
data += left_len;
|
|
data_len += left_len;
|
|
if(pHead_ToSend == NULL) {
|
|
pTail_ToSend = pHead_Sended;
|
|
pHead_ToSend = pTail_ToSend;
|
|
} else {
|
|
pTail_ToSend->next = pHead_Sended;
|
|
pTail_ToSend = pTail_ToSend->next;
|
|
}
|
|
pHead_Sended = pHead_Sended->next;
|
|
|
|
pTail_ToSend->next = NULL;
|
|
if(pHead_Sended == NULL)
|
|
{
|
|
os_printf("buf full\r\n");
|
|
break;
|
|
}
|
|
//os_printf(">666\r\n");
|
|
}
|
|
}
|
|
|
|
//os_printf(">>pHead_ToSend:0x%08x\r\n",pHead_ToSend);
|
|
|
|
if(pHead_ToSend == NULL) {
|
|
pTail_ToSend = pHead_Sended;
|
|
pHead_ToSend = pTail_ToSend;
|
|
|
|
pHead_Sended = pHead_Sended->next;
|
|
pTail_ToSend->next = NULL;
|
|
//system_os_post(2, 2, 0);
|
|
sdio_try_to_load();
|
|
}
|
|
return data_len;
|
|
}
|
|
|
|
static void sdio_try_to_load(void)
|
|
{
|
|
if((has_read == TRUE) && (pHead_ToSend != NULL))
|
|
{
|
|
rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
|
|
rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
|
|
//pHead_ToSend = pHead_ToSend->next;
|
|
has_read = FALSE;
|
|
//os_printf("SLC_INT_STATUS:0x%08x\r\n",READ_PERI_REG(SLC_INT_STATUS));
|
|
TRIG_TOHOST_INT();
|
|
}
|
|
}
|
|
|
|
static void sdio_read_done_process(void)
|
|
{
|
|
has_read = TRUE;
|
|
|
|
pHead_ToSend->tail = pHead_ToSend->buffer + SDIO_TOKEN_SIZE;
|
|
if(pHead_Sended) {
|
|
pTail_Sended->next = pHead_ToSend;
|
|
pTail_Sended = pTail_Sended->next;
|
|
}else {
|
|
pTail_Sended = pHead_ToSend;
|
|
pHead_Sended = pTail_Sended;
|
|
}
|
|
pHead_ToSend = pHead_ToSend->next;
|
|
pTail_Sended->next = NULL;
|
|
//os_printf(">>pHead_ToSend:0x%08x,pHead_Sended:0x%08x,0x%08x,0x%08x\r\n",pHead_ToSend,pHead_Sended,pHead_Sended->buffer,pHead_Sended->tail);
|
|
if(pHead_ToSend) {
|
|
rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
|
|
rx_buff_load_done(pHead_ToSend->tail - pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
|
|
has_read = FALSE;
|
|
//os_printf("intr trig\r\n");
|
|
//TRIG_TOHOST_INT();
|
|
} else if ((pHead_Sended != NULL) && (pHead_Sended->buffer != (pHead_Sended->tail- SDIO_TOKEN_SIZE))) {
|
|
pHead_ToSend = pHead_Sended;
|
|
pTail_ToSend = pHead_ToSend;
|
|
pHead_Sended = pHead_Sended->next;
|
|
pTail_ToSend->next = NULL;
|
|
|
|
rx_que.buf_ptr = (uint32)pHead_ToSend->buffer;
|
|
rx_buff_load_done(pHead_ToSend->tail- pHead_ToSend->buffer - SDIO_TOKEN_SIZE);
|
|
has_read = FALSE;
|
|
//os_printf("intr trig\r\n");
|
|
//TRIG_TOHOST_INT();
|
|
}
|
|
|
|
TRIG_TOHOST_INT();
|
|
}
|
|
|
|
bool sdio_register_recv_cb(sdio_recv_data_callback_t cb)
|
|
{
|
|
sdio_recv_data_callback_ptr = cb;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|