1. 程式人生 > >MTK SPI驅動開發

MTK SPI驅動開發

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 ;i<MAX_SPI_GROUP;i++)
    	{
    		if(SPI_IS_CLOSED != g_spi_description[i].spi_isopen_status)
    		{
    			return SPI_RESULT_OK;
    		}
    	}
    
    	spi_status = spi_close(g_spi_handle);
    	g_spi_handle = 0;
    	return spi_status;
    }
    
    SPI_RESULT m_spi_open(kal_uint32 group, SPI_CONFIG_PARAM_T* pConfigParam)
    {
    	//暫不清楚是否需要關閉在開啟,先執行關閉
    	SPI_RESULT spi_status = SPI_RESULT_OK;
    
    	if(0 == g_spi_mutexid)  g_spi_mutexid = kal_create_mutex("SPIMUTEX");
        
    	if(0 == g_spi_handle)
    	{
    		SPI_CS_CPIO_INIT;
    		//SPI_CS_PIN_CLR(0);
    		//SPI_CS_PIN_CLR(1);
    		g_spi_handle = spi_open(SPI_AVAIABLE_PORT);
    		spi_status = m_spi_configure(g_spi_handle,pConfigParam);
    	}
    	
    	if(SPI_RESULT_OK == spi_status)
    	{
    		dbg_print("init spi ok  g_spi_handle = %x \n",g_spi_handle);
    		g_spi_description[group].spi_isopen_status = SPI_IS_OPEN;
    		g_spi_description[group].spi_config_param.cs_setup_time = pConfigParam->cs_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模組自己控制,此程式碼僅供各位參考,多多指教。