MTK SPI驱动开发
1.由于SPI驱动 MTK封装的比较好,所以比较好处理。
唯一需要注意的是spi使用的全局Buffer必须要放在内存地址为“NONCACHEDZI”的区域
直接上代码管脚配置此处不再赘述
/*****************************************************************
简单封装的 SPI 驱动代码
Author
Date 20180915
*****************************************************************/
//外部GPIO函数声明:
//初始化GPIO方向
extern void GPIO_InitIO(char direction, kal_uint16 port);
//读指定GPIO口的管脚值
extern char GPIO_ReadIO(kal_uint16 port);
//输出指定电平到GPIO
extern void GPIO_WriteIO(char data, kal_uint16 port);
//设置GPIO的模式。GPIO模式为模式0.
extern void GPIO_ModeSetup(kal_uint16 port, kal_uint16 conf_dada);
//设置GPIO的上/下拉使能
extern void GPIO_PullenSetup(kal_uint16 port, kal_bool enable);
//设置GPIO端口为上拉还是下拉
extern void GPIO_PullSelSetup(kal_uint16 port, kal_bool pull_up);
void spi_delayms(unsigned int ms)
{
unsigned int x , y;
for(x = ms; x > 0; x--) /* 通过一定周期循环进行延时*/
for(y = 3000 ; y > 0 ; y--);
}
#define SPI_GROUP0_CS_PIN (18|0x80)
#define SPI_GROUP1_CS_PIN (14|0x80)
#define SPI_CS_CPIO_INIT GPIO_ModeSetup(SPI_GROUP0_CS_PIN, 0);\
GPIO_ModeSetup(SPI_GROUP1_CS_PIN, 0);\
GPIO_PullenSetup(SPI_GROUP0_CS_PIN, 0);\
GPIO_PullenSetup(SPI_GROUP1_CS_PIN, 0);\
GPIO_PullSelSetup(SPI_GROUP0_CS_PIN, 0);\
GPIO_PullSelSetup(SPI_GROUP1_CS_PIN, 0);\
GPIO_InitIO(1, SPI_GROUP0_CS_PIN);\
GPIO_InitIO(1, SPI_GROUP1_CS_PIN);\
GPIO_WriteIO(1, SPI_GROUP0_CS_PIN);\
GPIO_WriteIO(1, SPI_GROUP1_CS_PIN);
#define SPI_CS_PIN_SET(group) if(0 == group)\
GPIO_WriteIO(1, SPI_GROUP0_CS_PIN);\
else\
GPIO_WriteIO(1, SPI_GROUP1_CS_PIN);
#define SPI_CS_PIN_CLR(group) if(0 == group)\
GPIO_WriteIO(0, SPI_GROUP0_CS_PIN);\
else\
GPIO_WriteIO(0, SPI_GROUP1_CS_PIN);
//spi driver使用的buffer必须定义为non cachedrw 大小暂时为10k
#define SPI_WRITE_BUFF_MAXSIZE (1024*5)
#define SPI_READ_BUFF_MAXSIZE (1024*5)
//放在段空间为 NONCACHEDRW 的位置
#pragma arm section rwdata = "NONCACHEDRW", zidata = "NONCACHEDZI"
__align(4) kal_uint8 g_spi_write_buffer[SPI_WRITE_BUFF_MAXSIZE] = {0};
__align(4) kal_uint8 g_spi_read_buffer[SPI_READ_BUFF_MAXSIZE] = {0};
#pragma arm section rwdata, zidata
//目前设计只支持5组SPI调用
#define SPI_AVAIABLE_PORT 0
#define MAX_SPI_GROUP 5
typedef enum
{
SPI_IS_CLOSED,
SPI_IS_OPEN,
SPI_MAX_STATUS,
}SPI_ISOPEN;
typedef struct
{
SPI_ISOPEN spi_isopen_status;
SPI_CONFIG_PARAM_T spi_config_param;
}SPI_DESCRIPTION;
static SPI_HANDLE g_spi_handle;
static SPI_DESCRIPTION g_spi_description[MAX_SPI_GROUP]= {0};
//用于预防SPI操作过程中被打断的互斥变量
static kal_mutexid g_spi_mutexid = 0;
//开放我们可用的SPI只有PORT 0:
SPI_RESULT m_spi_configure(SPI_HANDLE handle, SPI_CONFIG_PARAM_T* pConfigParam)
{
return spi_configure(handle,pConfigParam);
}
SPI_RESULT m_spi_write(kal_uint32 group, void* pBuffer, kal_uint32 length, kal_uint32 count, SPI_CALLBACK fCB)
{
SPI_RESULT spi_status;
//如果此接口未打开,则返回ERROR
if(SPI_IS_OPEN != g_spi_description[group].spi_isopen_status)
{
return SPI_RESULT_ERROR;
}
//SPI 端口未打开
if(0 == g_spi_handle)
{
return SPI_RESULT_ERROR;
}
//spi_status = m_spi_configure(g_spi_handle,&g_spi_description[group].spi_config_param);
if(SPI_RESULT_OK != spi_status)
{
//return spi_status;
}
kal_take_mutex(g_spi_mutexid);
if(0 == group) SPI_CS_PIN_CLR(group);
memcpy(g_spi_write_buffer,(kal_uint8*)pBuffer,length);
spi_status = spi_write(g_spi_handle,g_spi_write_buffer,length,count,fCB);
if(0 == group) SPI_CS_PIN_SET(group);
kal_give_mutex(g_spi_mutexid);
return spi_status;
}
SPI_RESULT m_spi_read(kal_uint32 group,void* pBuffer, kal_uint32 length, kal_uint32 count, SPI_CALLBACK fCB)
{
SPI_RESULT spi_status;
//如果此接口未打开,则返回ERROR
if(SPI_IS_OPEN != g_spi_description[group].spi_isopen_status)
{
return SPI_RESULT_ERROR;
}
//SPI 端口未打开
if(0 == g_spi_handle)
{
return SPI_RESULT_ERROR;
}
//spi_status = m_spi_configure(g_spi_handle,&g_spi_description[group].spi_config_param);
if(SPI_RESULT_OK != spi_status)
{
//return spi_status;
}
kal_take_mutex(g_spi_mutexid);
if(0 == group) SPI_CS_PIN_CLR(group);
spi_status = spi_read(g_spi_handle,g_spi_read_buffer,length,count,fCB);
if(0 == group) SPI_CS_PIN_SET(group);
if(SPI_RESULT_OK == spi_status)
{
memcpy((kal_uint8*)pBuffer,g_spi_read_buffer,length);
kal_give_mutex(g_spi_mutexid);
return spi_status;
}
kal_give_mutex(g_spi_mutexid);
return spi_status;
}
SPI_RESULT m_spi_readwrite(kal_uint32 group, void* pOutBuffer, void* pInBuffer, kal_uint32 length, kal_uint32 count, SPI_CALLBACK fCB)
{
SPI_RESULT spi_status;
//如果此接口未打开,则返回ERROR
if(SPI_IS_OPEN != g_spi_description[group].spi_isopen_status)
{
return SPI_RESULT_ERROR;
}
//SPI 端口未打开
if(0 == g_spi_handle)
{
return SPI_RESULT_ERROR;
}
spi_status = m_spi_configure(g_spi_handle,&g_spi_description[group].spi_config_param);
if(SPI_RESULT_OK != spi_status)
{
return spi_status;
}
memcpy(g_spi_write_buffer,(kal_uint8*)pInBuffer,length);
spi_status = spi_readwrite(g_spi_handle,g_spi_read_buffer,g_spi_write_buffer,length,count,fCB);
if(SPI_RESULT_OK == spi_status)
{
memcpy((kal_uint8*)pOutBuffer,g_spi_read_buffer,length);
dbg_print("end to readwrite data to spi buffer\n");
return spi_status;
}
return spi_status;
}
SPI_RESULT m_spi_power_ctrl(kal_bool bPowerOn)
{
return spi_power_ctrl(g_spi_handle,bPowerOn);
}
//所有的SPIGROUP都是关闭状态,才会调用SPI关闭函数,否则只是置SPI的开关状态为关闭并返回OK
SPI_RESULT m_spi_close(kal_uint32 group)
{
SPI_RESULT spi_status;
kal_uint8 i = 0;
g_spi_description[group].spi_isopen_status = SPI_IS_CLOSED;
for(i = 0 ;ics_setup_time;
g_spi_description[group].spi_config_param.cs_hold_time = pConfigParam->cs_hold_time;
g_spi_description[group].spi_config_param.cs_idle_time = pConfigParam->cs_idle_time;
g_spi_description[group].spi_config_param.clk_low_time = pConfigParam->clk_low_time;
g_spi_description[group].spi_config_param.clk_high_time = pConfigParam->clk_high_time;
g_spi_description[group].spi_config_param.tx_msbf = pConfigParam->tx_msbf;
g_spi_description[group].spi_config_param.rx_msbf = pConfigParam->rx_msbf;
g_spi_description[group].spi_config_param.tx_endian = pConfigParam->tx_endian;
g_spi_description[group].spi_config_param.rx_endian = pConfigParam->rx_endian;
g_spi_description[group].spi_config_param.clk_polarity = pConfigParam->clk_polarity;
g_spi_description[group].spi_config_param.clk_fmt = pConfigParam->clk_fmt;
}
else
{
g_spi_description[group].spi_isopen_status = SPI_IS_CLOSED;
}
return spi_status;
}
由于笔者的硬件系统CS1挂载的是FLASH来使用文件系统,所以CS1的的片选由Flash模块自己控制,此代码仅供各位参考,多多指教。