|
发表于 2020-11-7 17:29:49
|
显示全部楼层
本帖最后由 chun2495 于 2020-11-7 17:31 编辑
给楼主上传个自己写的模拟io的程序,linux的。原理是一样。
- /*
- * 说明:w25q驱动程序,在android上运行。
- * 日期:2020.04.07
- * 作者:chun307
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/i2c.h>
- #include <linux/input.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <linux/gpio.h>
- #include <linux/platform_device.h>
- #include <linux/miscdevice.h>
- #include <asm/uaccess.h>
- #define DEVICE_NAME "epcs_ctl"
- #define DRIVER_NAME "epcs_ctl"
- #define SPI_CS IMX_GPIO_NR(2, 28)//MX6Q_PAD_EIM_EB0__GPIO_2_28
- #define SPI_CLK IMX_GPIO_NR(2, 29)//MX6Q_PAD_EIM_EB1__GPIO_2_29
- #define SPI_TXD IMX_GPIO_NR(3, 26)//MX6Q_PAD_EIM_D26__GPIO_3_26
- #define SPI_RXD IMX_GPIO_NR(3, 27)//MX6Q_PAD_EIM_D27__GPIO_3_27
- static int epcss_out[] = {
- SPI_CS,
- SPI_CLK,
- SPI_TXD,
- };
- static int epcss_in[] = {
- SPI_RXD,
- };
- #define GPIO_NUM_OUT ARRAY_SIZE(epcss_out)
- #define GPIO_NUM_IN ARRAY_SIZE(epcss_in)
- #define GPIO_HIGH 1
- #define GPIO_LOW 0
- #define CS_OUT() gpio_direction_output(SPI_CS, 1)
- #define CS_HIGH() gpio_set_value(SPI_CS, GPIO_HIGH)
- #define CS_LOW() gpio_set_value(SPI_CS, GPIO_LOW)
- #define CLK_OUT() gpio_direction_output(SPI_CLK, 1)
- #define CLK_HIGH() gpio_set_value(SPI_CLK, GPIO_HIGH)
- #define CLK_LOW() gpio_set_value(SPI_CLK, GPIO_LOW)
- #define TXD_OUT() gpio_direction_output(SPI_TXD, 1)
- #define TXD_HIGH() gpio_set_value(SPI_TXD, GPIO_HIGH)
- #define TXD_LOW() gpio_set_value(SPI_TXD, GPIO_LOW)
- #define RXD_IN() gpio_direction_input(SPI_RXD)
- #define RXD_GET() gpio_get_value(SPI_RXD)
- //页大小和页数目
- #define EPCS_Page_Size 256
- #define EPCS_Page_Max 8192
- //功能寄存器地址
- #define WRITE_ENABLE 0X06
- #define WRITE_DISABLE 0X04
- #define READ_ID 0X9F
- #define READ_STAUS_REG 0X05
- #define WRITE_STAUS_REG 0X01
- #define READ_DATA 0X03
- #define FAST_READ_DATA 0X0B
- #define PAGE_PROGRAM 0X02
- #define SECTOR_ERASE 0XD8
- #define BULK_ERASE 0XC7
- #define DEEP_POWER_DOWN 0XB9
- #define WAKE_UP 0XAB
- unsigned char SPI_Flash_Read()
- {
- unsigned char i = 0;
- unsigned char temp = 0; //read data
-
- for (i = 0; i < 8; i++){ // 8 bits Data
- CLK_LOW();
- // udelay(1);
- CLK_HIGH();
- temp <<= 1;
- temp |= RXD_GET();
- // udelay(1);
- }
- return temp;
- }
- void SPI_Flash_Write(unsigned char data)
- {
- unsigned char i;
-
- for (i = 0; i < 8; i++){
- CLK_LOW();
- // udelay(1);
- if (data & 0x80){
- TXD_HIGH();
- } else{
- TXD_LOW();
- }
- CLK_HIGH();
- // udelay(1);
- data <<= 1;
- }
- }
- void EPCS_Write_Enable(void)
- {
- CS_LOW();
- SPI_Flash_Write(WRITE_ENABLE);
- CS_HIGH();
- }
- void EPCS_Write_Disable(void)
- {
- CS_LOW();
- SPI_Flash_Write(WRITE_DISABLE);
- CS_HIGH();
- }
- unsigned int EPCS_Read_Id()
- {
- unsigned char i;
- unsigned char id[3];
-
- CS_LOW();
- SPI_Flash_Write(READ_ID);
- for(i = 0; i < 3; i++){
- id[i] = SPI_Flash_Read();
- }
- CS_HIGH();
- // printk("ID: 0X%X 0X%X 0X%X\n", id[0], id[1], id[2]);
- return (unsigned int)((id[0]<<16) | (id[1]<< 8) | id[2]);
- }
- unsigned char EPCS_Read_Status_Reg(void)
- {
- unsigned char sta;
-
- CS_LOW();
- SPI_Flash_Write(READ_STAUS_REG);
- sta= SPI_Flash_Read();
- CS_HIGH();
- return sta;
- }
- void EPCS_Write_Status_Reg(unsigned char reg)
- {
- CS_LOW();
- SPI_Flash_Write(WRITE_STAUS_REG);
- SPI_Flash_Write(reg);
- CS_HIGH();
- }
- void EPCS_Sector_Erase(unsigned int addr)
- {
- addr *= 65536; //扇区*页(64K)
- EPCS_Write_Enable();
-
- CS_LOW();
- SPI_Flash_Write(SECTOR_ERASE);
- SPI_Flash_Write((addr>>16) & 0xff);
- SPI_Flash_Write((addr>>8) & 0xff);
- SPI_Flash_Write(addr & 0xff);
- CS_HIGH();
-
- while(EPCS_Read_Status_Reg()&0x01);
- }
- void EPCS_Bulk_Erase(void)
- {
- EPCS_Write_Enable();
-
- CS_LOW();
- SPI_Flash_Write(BULK_ERASE);
- CS_HIGH();
-
- while(EPCS_Read_Status_Reg()&0x01);
- }
- void EPCS_Deep_Power_Down(void)
- {
- CS_LOW();
- SPI_Flash_Write(DEEP_POWER_DOWN);
- CS_HIGH();
- }
- unsigned char EPCS_Wake_Up(void)
- {
- unsigned char res;
-
- CS_LOW();
- SPI_Flash_Write(WAKE_UP);
- SPI_Flash_Write(0);
- SPI_Flash_Write(0);
- SPI_Flash_Write(0);
- res = SPI_Flash_Read();
- CS_HIGH();
- return res;
- }
- //读数据,自动翻页,addr为字节地址
- void EPCS_Read_Data(unsigned int addr, unsigned int len, unsigned char *buf)
- {
- unsigned int i;
-
- CS_LOW();
- SPI_Flash_Write(READ_DATA);
- SPI_Flash_Write((addr>>16) & 0xff);//扇区:16个
- SPI_Flash_Write((addr>>8) & 0xff); //页:256页
- SPI_Flash_Write(addr & 0xff);//页内地址:256字节
- for(i = 0; i < len; i++){
- buf[i] = SPI_Flash_Read();
- }
- CS_HIGH();
- }
- //快速读数据
- void EPCS_Fast_Read_Data(unsigned int addr, unsigned int len, unsigned char *buf)
- {
- unsigned int i;
- CS_LOW();
- SPI_Flash_Write(FAST_READ_DATA);
- SPI_Flash_Write((addr>>16) & 0xff);
- SPI_Flash_Write((addr>>8) & 0xff);
- SPI_Flash_Write(addr & 0xff);
- SPI_Flash_Write(0);
- for(i = 0; i < len; i++){
- buf[i] = SPI_Flash_Read();
- }
- CS_HIGH();
- }
- //页编程函数,页编程前一定要进行区擦除!
- void EPCS_Page_Program(unsigned int addr, unsigned short len, unsigned char *buf)
- {
- unsigned int i;
-
- EPCS_Write_Enable();
-
- CS_LOW();
- SPI_Flash_Write(PAGE_PROGRAM);
- SPI_Flash_Write((addr>>16) & 0xff);
- SPI_Flash_Write((addr>>8) & 0xff);
- SPI_Flash_Write(addr & 0xff);
- for(i = 0; i < len; i++)
- SPI_Flash_Write(buf[i]);
- CS_HIGH();
-
- while(EPCS_Read_Status_Reg()&0x01);
- }
- /*****************************************************************************
- *函数名称:void M25PXX_Write_NoCheck(unsigned char* pBuffer,unsigned int WriteAddr,u16 NumByteToWrite)
- *功 能:无检验写SPI FLASH,具有自动换页功能
- *说 明:必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
- *输入参数:pBuffer:数据存储区,WriteAddr:开始写入的地址(24bit),
- NumByteToWrite:要写入的字节数(最大65535)
- *输出参数:无
- ******************************************************************************/
- void EPCS_Write_NoCheck(unsigned char * pBuffer, unsigned int WriteAddr, unsigned int NumByteToWrite)
- {
- unsigned int pageremain;
-
- pageremain = 256 - WriteAddr%256; //单页剩余的字节数
- if(NumByteToWrite <= pageremain) pageremain = NumByteToWrite;//不大于256个字节
- while(1){
- EPCS_Page_Program(WriteAddr, pageremain, pBuffer);//写页
- if(NumByteToWrite == pageremain) break;//写入结束了
- else{ //NumByteToWrite>pageremain
- pBuffer += pageremain;
- WriteAddr += pageremain;
- NumByteToWrite -= pageremain; //减去已经写入了的字节数
- if(NumByteToWrite > 256) pageremain = 256; //一次可以写入256个字节
- else pageremain = NumByteToWrite; //不够256个字节了
- }
- }
- }
- static int okmx6q_epcs_open(struct inode *inode, struct file *file) {
- return 0;
- }
- static int okmx6q_epcs_close(struct inode *inode, struct file *file) {
- return 0;
- }
- //count(最大65535)
- static ssize_t okmx6q_epcs_read(struct file *filp, char __user *buf, size_t count, loff_t *ofs)
- {
- printk("EPCS read count is %d, ofs is %d\n", count, *ofs);
-
- unsigned int i;
- unsigned int addr = *ofs;
- unsigned int len = count;
- CS_LOW();
- SPI_Flash_Write(READ_DATA);
- SPI_Flash_Write((addr>>16) & 0xff);
- SPI_Flash_Write((addr>>8) & 0xff);
- SPI_Flash_Write(addr & 0xff);
-
- for(i = 0; i < len; i++){
- buf[i] = SPI_Flash_Read();
- }
- CS_HIGH();
-
- printk("EPCS read done!\n");
- return 0;
- }
- /*****************************************************************************
- *函数名称:void M25PXX_Write(unsigned char* pBuffer,unsigned int WriteAddr,u16 NumByteToWrite)
- *功 能:写SPI FLASH,在指定地址开始写入指定长度的数据
- *说 明:该函数带擦除操作!
- *输入参数:pBuffer:数据存储区,WriteAddr:开始写入的地址(24bit),
- NumByteToWrite:要写入的字节数(最大65535)
- *输出参数:无
- ******************************************************************************/
- unsigned char EPCS_BUFFER[65536];
- static ssize_t okmx6q_epcs_write(struct file *filp, const char __user *pBuffer, size_t NumByteToWrite, loff_t *ofs)
- {
-
- unsigned int WriteAddr = *ofs;
- unsigned int secpos;
- unsigned int secoff;
- unsigned int secremain;
- unsigned int i;
- unsigned char *EPCS_BUF;
-
- printk("EPCS Write Len : %d, Addr : %d\n", NumByteToWrite, WriteAddr);
-
- EPCS_BUF = EPCS_BUFFER; //得到数值缓存区
- secpos = WriteAddr/65536; //扇区地址
- secoff = WriteAddr%65536; //在扇区内的偏移
- secremain = 65536 - secoff; //扇区剩余空间大小
- if(NumByteToWrite <= secremain) secremain = NumByteToWrite;//不大于64K个字节
- while(1){
- printk("read start...\n");
- EPCS_Read_Data(secpos*65536, 65536, EPCS_BUF);//读出整个扇区的内容
- for(i = 0; i < secremain; i++){//校验数据
- if(EPCS_BUF[secoff + i] != 0XFF) break;//需要擦除
- }
- printk("write start...\n");
- if(i < secremain){//需要擦除
- EPCS_Sector_Erase(secpos);//擦除这个扇区
- for(i = 0; i < secremain; i++){//复制
- EPCS_BUF[i + secoff] = pBuffer[i];
- }
- EPCS_Write_NoCheck(EPCS_BUF, secpos*65536, 65536);//写入整个扇区
- }else EPCS_Write_NoCheck(pBuffer, WriteAddr, secremain);//写已经擦除了的,直接写入扇区剩余区间.
- if(NumByteToWrite == secremain) break;//写入结束了
- else{//写入未结束
- secpos++; //扇区地址增1
- secoff = 0; //偏移位置为0
- pBuffer += secremain; //指针偏移
- WriteAddr += secremain; //写地址偏移
- NumByteToWrite -= secremain; //字节数递减
- if(NumByteToWrite > 65536) secremain = 65536; //下一个扇区还是写不完
- else secremain = NumByteToWrite; //下一个扇区可以写完了
- }
- printk("EPCS write done!\n");
- }
- return 0;
- }
- /* static ssize_t okmx6q_epcs_write(struct file *filp, const char __user *pBuffer, size_t NumByteToWrite, loff_t *ofs)
- {
- unsigned int i;
- unsigned int addr = *ofs;
- unsigned int len = NumByteToWrite;
-
- printk("EPCS Write Len : %d, Addr : %d\n", len, addr);
-
- EPCS_Sector_Erase(addr/65536);//擦除这个扇区
-
- EPCS_Write_Enable();
-
- CS_LOW();
- SPI_Flash_Write(PAGE_PROGRAM);
- SPI_Flash_Write((addr>>16) & 0xff);
- SPI_Flash_Write((addr>>8) & 0xff);
- SPI_Flash_Write(addr & 0xff);
- for(i = 0; i < len; i++){
- SPI_Flash_Write(pBuffer[i]);
- }
- CS_HIGH();
-
- while(EPCS_Read_Status_Reg()&0x01);
-
- printk("EPCS write done!\n");
- return 0;
- } */
- /* static ssize_t okmx6q_epcs_write(struct file *filp, const char __user *pBuffer, size_t NumByteToWrite, loff_t *ofs)
- {
- unsigned int i;
- unsigned int addr = *ofs;
- unsigned int len = NumByteToWrite;
-
- printk("EPCS Write Len : %d, Addr : %d\n", len, addr);
-
- EPCS_Sector_Erase(addr/65536);//擦除这个扇区
-
- EPCS_Write_NoCheck(pBuffer, addr, len);
-
- printk("EPCS write done!\n");
- return 0;
- } */
- static long okmx6q_epcs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
- {
- unsigned int ret = 0;
-
- printk("cmd is %d, arg is %d\n", cmd, arg);
-
- switch(cmd) {
- case 0: ret = EPCS_Read_Id();
- break;
- default:
- printk("error\n");
- return -EINVAL;
- }
- return ((long)ret);
- }
- static struct file_operations okmx6q_epcs_ops = {
- .owner = THIS_MODULE,
- .open = okmx6q_epcs_open,
- .release = okmx6q_epcs_close,
- .read = okmx6q_epcs_read,
- .write = okmx6q_epcs_write,
- .unlocked_ioctl = okmx6q_epcs_ioctl,
- };
- static struct miscdevice okmx6q_misc_dev = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DEVICE_NAME,
- .fops = &okmx6q_epcs_ops,
- };
- static int okmx6q_epcs_probe(struct platform_device *pdev)
- {
- int ret;
-
- //SPI_CS
- ret = gpio_request(SPI_CS, DEVICE_NAME);
- if (ret) {
- printk("request SPI_CS failed, ret= %d\n", ret);
- return ret;
- }
- else{
- gpio_direction_output(SPI_CS, 1);
- gpio_set_value(SPI_CS, 1);
- }
-
- //SPI_CLK
- ret = gpio_request(SPI_CLK, DEVICE_NAME);
- if (ret) {
- printk("request SPI_CLK failed, ret= %d\n", ret);
- return ret;
- }
- else{
- gpio_direction_output(SPI_CLK, 1);
- gpio_set_value(SPI_CLK, 1);
- }
-
- //SPI_TXD
- ret = gpio_request(SPI_TXD, DEVICE_NAME);
- if (ret) {
- printk("request SPI_TXD failed, ret= %d\n", ret);
- return ret;
- }
- else{
- gpio_direction_output(SPI_TXD, 1);
- gpio_set_value(SPI_TXD, 1);
- }
-
- //SPI_RXD
- ret = gpio_request(SPI_RXD, DEVICE_NAME);
- if (ret) {
- printk("request SPI_RXD failed, ret= %d\n", ret);
- return ret;
- }
- else{
- gpio_direction_input(SPI_RXD);
- }
-
- ret = misc_register(&okmx6q_misc_dev);
- printk(DEVICE_NAME "\tinitialized\n");
- return 0;
- }
- static int okmx6q_epcs_remove (struct platform_device *pdev)
- {
- int i;
-
- for(i = 0; i < GPIO_NUM_OUT; i++){
- gpio_free(epcss_out[i]);
- }
- for(i = 0; i < GPIO_NUM_IN; i++){
- gpio_free(epcss_in[i]);
- }
- misc_deregister(&okmx6q_misc_dev);
- return 0;
- }
- static int okmx6q_epcs_suspend (struct platform_device *pdev, pm_message_t state)
- {
- printk("epcs suspend!\n");
- return 0;
- }
- static int okmx6q_epcs_resume (struct platform_device *pdev)
- {
- printk("epcs resume!\n");
- return 0;
- }
- static struct platform_driver okmx6q_epcs_driver = {
- .probe = okmx6q_epcs_probe,
- .remove = okmx6q_epcs_remove,
- .suspend = okmx6q_epcs_suspend,
- .resume = okmx6q_epcs_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
- };
- static int __init okmx6q_epcs_dev_init(void) {
- return platform_driver_register(&okmx6q_epcs_driver);
- }
- static void __exit okmx6q_epcs_dev_exit(void) {
- platform_driver_unregister(&okmx6q_epcs_driver);
- }
- module_init(okmx6q_epcs_dev_init);
- module_exit(okmx6q_epcs_dev_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("chun307");
- MODULE_DESCRIPTION("OKMX6Q EPCS Driver");
复制代码 |
|