【1】FPGA端
【1.1】頂層模塊分爲SPI接口、寄存器組、PLL這三個部分。node
1 module top( 2 input clkin, 3 4 // spi 5 output arm_spi_miso, 6 input arm_spi_mosi, 7 input arm_spi_cs, 8 input arm_spi_clk 9 ); 10 11 reg [15:0] reg_sum = 12; 12 13 // reg_array 14 wire [15:0] status_sum; 15 wire [15:0] attr_sum; 16 wire [15:0] attr_fibre_len; 17 18 // test 19 assign status_sum = reg_sum; 20 21 // reg_array 和 spi_slave 之間的接線 22 wire [6:0] m_addr; 23 wire [15:0] m_din; 24 wire [15:0] m_dout; 25 wire m_we; 26 wire m_latch; 27 28 // 29 wire sys_clk; 30 31 reg_array reg_array_ins( 32 // to spi_slave 33 .addr(m_addr), 34 .we(m_we), 35 .din(m_din), 36 .dout(m_dout), 37 .latch(m_latch), 38 39 // wire 40 .status_sum, 41 42 .attr_sum, 43 .attr_fibre_len 44 ); 45 46 spi_slave spi_slave_ins( 47 // pin 48 .spi_cs(arm_spi_cs), 49 .spi_clk(arm_spi_clk), 50 .spi_mosi(arm_spi_mosi), 51 .spi_miso(arm_spi_miso), 52 53 // sysclk 54 .sys_clk(sys_clk), 55 56 // to reg_array 57 .m_addr(m_addr), 58 .m_din(m_dout), 59 .m_dout(m_din), 60 .m_we(m_we), 61 .m_latch(m_latch) 62 ); 63 pll0 pll0_ins( 64 .CLK_IN1(clkin), 65 .CLK_OUT1(sys_clk) 66 ); 67 endmodule
【1.2】SPI接口部分,在SPI_CLK的上升沿鎖存輸入,降低沿移位輸出,幀結構爲7bit addr+1bit we+16bit data。經過晶振時鐘來檢測CS的兩個邊沿,置msg_begin標記,並在spi_clk的第一個上升沿初始化計數器。
若是spi_clk不是從GLCK腳輸入的,則也能夠用晶振時鐘或PLL輸出來檢測spi_clk的上升和降低沿,固然spi_clk最高速率通常不能超過檢測時鐘頻率的1/4。linux
1 module spi_slave( 2 input spi_cs, 3 input spi_clk, 4 input spi_mosi, 5 output spi_miso, 6 7 input sys_clk, 8 9 output [6:0] m_addr, 10 input [15:0] m_din, 11 output [15:0] m_dout, 12 output m_we, // 1=write 13 output m_latch // read/write at the rasing edge 14 ); 15 reg [4:0] shift_count = 24; 16 reg [15:0] reg_data_in = 0; // 從mosi接收的數據 17 reg [15:0] reg_data_out = 0; // 發送往miso的數據 18 19 reg reg_we = 0; 20 assign m_we = reg_we; 21 22 assign spi_miso = reg_data_out[15]; 23 assign m_addr = reg_data_in[6:0]; 24 assign m_dout = reg_data_in; // 送往reg_array 25 reg reg_latch = 1; 26 27 // CS邊沿檢測 28 reg msg_begin = 0; 29 reg [2:0] reg_cs = 3'b111; 30 always @(posedge sys_clk) 31 begin 32 reg_cs <= {reg_cs[1:0], spi_cs}; 33 34 if(reg_cs[2:1] == 2'b10) 35 begin 36 msg_begin <= 1; 37 end 38 39 if(reg_cs[2:1] == 2'b00 && shift_count != 24) 40 begin 41 msg_begin <= 0; 42 end 43 44 if(reg_cs[2:1] == 2'b01) 45 begin 46 msg_begin <= 1; 47 end 48 end 49 50 always @(posedge spi_clk) 51 begin 52 if(spi_cs == 0) 53 begin 54 if(msg_begin == 1) 55 begin 56 shift_count <= 1; // 初始化shift_count 57 end else begin 58 if(shift_count < 24) 59 begin 60 shift_count <= shift_count + 1'b1; 61 end 62 end 63 64 reg_data_in <= {reg_data_in[14:0], spi_mosi}; // 地址在第7個降低沿生效, 65 end 66 end 67 68 always @(negedge spi_clk) 69 begin 70 if(spi_cs == 0) 71 begin 72 if(shift_count == 1) // 拉低latch 73 begin 74 reg_latch <= 0; 75 reg_we <= 0; // 默認讀取 76 end 77 if(shift_count == 7) // 地址已經在第7個上升沿鎖存完成,讓reg_array準備數據 78 begin 79 reg_latch <= 1; 80 end 81 if(shift_count == 8) // 拉低latch 82 begin 83 reg_latch <= 0; 84 end 85 86 // 準備讀取數據 87 if(shift_count == 8) // 寫入時也輸出 88 begin 89 reg_data_out <= m_din; 90 reg_we <= reg_data_in[0]; // 鎖存讀寫位備用 91 end 92 // 移位輸出 93 if(shift_count > 8) // 寫入時也輸出 94 begin 95 reg_data_out <= {reg_data_out[14:0], 1'b0}; 96 end 97 98 // 處理寫入 99 if(shift_count == 24 && reg_we == 1) 100 begin 101 reg_latch <= 1; 102 end 103 end 104 end 105 assign m_latch = reg_latch; 106 107 endmodule
【1.3】寄存器組則是對SPI來的地址譯碼和讀寫。在latch的上升沿,WE=1寫入數據,WE=0讀取數據。ide
1 module reg_array( 2 input [6:0] addr, 3 input we, 4 input [15:0] din, 5 output reg [15:0] dout, 6 input latch, 7 8 input [15:0] status_sum, 9 10 output [15:0] attr_sum, 11 output [15:0] attr_fibre_len 12 ); 13 localparam REG_ATTR_SUM = 0; 14 localparam REG_ATTR_FIBRE_LEN = 1; 15 16 localparam REG_STATUS_SUM = 32; 17 18 reg [6:0] reg_addr = 0; 19 reg [15:0] reg_attr_sum = 2048; 20 reg [15:0] reg_attr_fibre_len = 26000; 21 22 assign attr_sum = reg_attr_sum; 23 assign attr_fibre_len = reg_attr_fibre_len; 24 25 always @(posedge latch) 26 begin 27 if(we == 0) 28 begin 29 case (addr) 30 REG_ATTR_SUM: dout = reg_attr_sum; 31 REG_ATTR_FIBRE_LEN: dout = reg_attr_fibre_len; 32 33 REG_STATUS_SUM: dout = status_sum; 34 default: dout = 0; 35 endcase 36 end 37 end 38 39 always @(posedge latch) 40 begin 41 if(we == 0) 42 begin 43 reg_addr <= addr; 44 end 45 if(we == 1) 46 begin 47 case (reg_addr) 48 REG_ATTR_SUM: reg_attr_sum <= din; 49 REG_ATTR_FIBRE_LEN: reg_attr_fibre_len <= din; 50 default:; 51 endcase 52 end 53 end 54 55 endmodule
【2】ARM端
【2.1】使用GPIO模擬SPI的驅動——簡單、通用、速度慢。ui
1 #include <linux/miscdevice.h> 2 #include <linux/kernel.h> 3 #include <linux/module.h> 4 #include <linux/fs.h> 5 #include <linux/types.h> 6 #include <linux/moduleparam.h> 7 #include <linux/ioctl.h> 8 #include <linux/string.h> 9 #include <mach/gpio.h> 10 #include <mach/mux.h> 11 #include <asm/uaccess.h> 12 #include <linux/interrupt.h> 13 #include "spi_fpga.h" 14 15 static char *spi1_gpio_mux_name[] = { 16 "GPIO0_7", 17 "GPIO0_10", 18 "GPIO0_8", 19 //"GPIO0_9", 20 "GPIO1_15" 21 }; 22 23 #define PINMUX_SET_NUM 4 24 25 static unsigned char mode_old_list[PINMUX_SET_NUM]; 26 static unsigned char flag_list[PINMUX_SET_NUM]; 27 28 #define SPI_CLK GPIO_TO_PIN(0, 7) 29 #define SPI_MOSI GPIO_TO_PIN(0, 10) 30 #define SPI_MISO GPIO_TO_PIN(1, 15) // GPIO_TO_PIN(0, 9) 31 #define SPI_CS GPIO_TO_PIN(0, 8) 32 33 static enum SPI_GPIO_MODE__E mode; 34 static uint16_t trans_len=0; 35 int irq = 0; 36 37 void spi_gpio_trans(void *user_addr) 38 { 39 int i=0; 40 int j=0; 41 42 uint8_t buf[trans_len]; 43 memset(buf,0,sizeof(buf)); 44 45 copy_from_user(buf,user_addr, sizeof(buf)); 46 #if 0 47 printk("buf="); 48 for(i = 0; i < trans_len; i++) 49 printk("%02x,",buf[i]); 50 printk("\n"); 51 #endif 52 // 設置初始狀態 53 if(mode < 2)//CPOL=0 54 gpio_set_value(SPI_CLK, 0); 55 else 56 gpio_set_value(SPI_CLK, 1); 57 //片選初始爲高 58 gpio_set_value(SPI_CS, 1); 59 // 傳輸開始,片選爲低 60 gpio_set_value(SPI_CS, 0); 61 62 for(i = 0; i < trans_len; i++) 63 { 64 uint8_t byte_out = buf[i]; 65 uint8_t byte_in = 0; 66 for(j = 0; j < 8; j++) 67 { 68 byte_in <<= 1; 69 if(mode & 1) // CPHA=1,時鐘的降低沿輸出數據 70 { 71 gpio_set_value(SPI_CLK, 1); 72 73 if(byte_out & 0x80) 74 gpio_set_value(SPI_MOSI, 1); 75 else 76 gpio_set_value(SPI_MOSI, 0); 77 78 gpio_set_value(SPI_CLK, 0); 79 80 if(gpio_get_value(SPI_MISO) != 0) byte_in |= 1; 81 } 82 else// 時鐘的上升沿輸出數據 83 { 84 gpio_set_value(SPI_CLK, 0); 85 86 if(byte_out & 0x80) 87 gpio_set_value(SPI_MOSI, 1); 88 else 89 gpio_set_value(SPI_MOSI, 0); 90 91 gpio_set_value(SPI_CLK, 1); 92 93 if(gpio_get_value(SPI_MISO) != 0) byte_in |= 1; 94 } 95 96 byte_out <<= 1; 97 } 98 buf[i] = byte_in; 99 } 100 #if 0 101 printk("buf="); 102 for(i = 0; i < trans_len; i++) 103 printk("%02x,",buf[i]); 104 printk("\n"); 105 #endif 106 // 設置時鐘線狀態 107 if(mode < 2)//CPOL=0 108 gpio_set_value(SPI_CLK, 0); 109 else 110 gpio_set_value(SPI_CLK, 1); 111 // 傳輸結束,片選爲高 112 gpio_set_value(SPI_CS, 1); 113 114 copy_to_user(user_addr, buf, sizeof(buf)); 115 } 116 //static int spi1_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) 117 static long spi_ioctl(struct file *inode, unsigned int cmd, unsigned long arg) 118 { 119 /* 檢測命令的有效性 */ 120 //if (_IOC_TYPE(cmd) != SPI_GPIO_IOC__MAGIC) 121 //return -EINVAL; 122 //if (_IOC_NR(cmd) > SPI_GPIO_IOC__MAXNR) 123 //return -EINVAL; 124 //uint8_t in = 0; 125 switch(cmd) 126 { 127 case SPI_GPIO_IOC__SET_MODE: 128 mode = arg; 129 printk("mode=%d\n",mode); 130 break; 131 case SPI_GPIO_IOC__SET_LEN: 132 trans_len = arg; 133 printk("trans_len=%d\n",trans_len); 134 break; 135 case SPI_GPIO_IOC__TRANS: 136 spi_gpio_trans((void*)arg); 137 138 break; 139 default: 140 break; 141 } 142 return 0; 143 } 144 145 static int spi_open(struct inode *inode, struct file *filp) 146 { 147 return 0; 148 } 149 static int spi_release(struct inode *inode, struct file *filp) 150 { 151 return 0; 152 } 153 154 static struct file_operations spi_fops = 155 { 156 .owner = THIS_MODULE, 157 .open = spi_open, 158 .release = spi_release, 159 .unlocked_ioctl = spi_ioctl 160 }; 161 162 static struct miscdevice misc = { 163 .minor = MISC_DYNAMIC_MINOR, 164 .name = "spi_fpga", //此名稱將顯示在/dev目錄下面 165 .fops = &spi_fops, 166 }; 167 168 static int __init dev_init(void) 169 { 170 int i; 171 int ret; 172 173 // 設置引腳複用 174 memset(flag_list, 0, PINMUX_SET_NUM); 175 for (i = 0; i < PINMUX_SET_NUM; i++) { 176 ret = davinci_cfg_reg_name(spi1_gpio_mux_name[i], 177 &mode_old_list[i], &flag_list[i]); 178 } 179 // 申請gpio佔用 180 ret = gpio_request(SPI_CLK, "SPI_CLK"); 181 if (ret) 182 { 183 pr_warning("Fail to request SPI_CLK PIN.\n"); 184 goto INIT_FAILED0; 185 } 186 ret = gpio_request(SPI_MOSI, "SPI_MOSI"); 187 if (ret) 188 { 189 pr_warning("Fail to request SPI_MOSI PIN.\n"); 190 goto INIT_FAILED1; 191 } 192 ret = gpio_request(SPI_MISO, "SPI_MISO"); 193 if (ret) 194 { 195 pr_warning("Fail to request SPI_MISO PIN.\n"); 196 goto INIT_FAILED2; 197 } 198 ret = gpio_request(SPI_CS, "SPI_CS"); 199 if (ret) 200 { 201 pr_warning("Fail to request SPI_CS PIN.\n"); 202 goto INIT_FAILED3; 203 } 204 // 設置gpio方向和初始狀態 205 gpio_direction_output(SPI_CLK, 0); 206 gpio_direction_output(SPI_MOSI, 0); 207 gpio_direction_output(SPI_CS, 1); 208 gpio_direction_input(SPI_MISO); 209 210 printk ("spi_fpga initialized\n"); 211 ret = misc_register(&misc); 212 213 return ret; 214 INIT_FAILED3: 215 gpio_free(SPI_CS); 216 INIT_FAILED2: 217 gpio_free(SPI_MISO); 218 INIT_FAILED1: 219 gpio_free(SPI_MOSI); 220 INIT_FAILED0: 221 gpio_free(SPI_CLK); 222 return -1; 223 } 224 225 static void __exit dev_exit(void) 226 { 227 int i = 0; 228 gpio_free(SPI_CLK); 229 gpio_free(SPI_MOSI); 230 gpio_free(SPI_MISO); 231 gpio_free(SPI_CS); 232 233 for (i = 0; i < PINMUX_SET_NUM; i++) { 234 davinci_cfg_reg_name(spi1_gpio_mux_name[i], 235 &mode_old_list[i], &flag_list[i]); 236 } 237 238 misc_deregister(&misc); 239 printk("spi_fpga unloaded\n"); 240 } 241 242 module_init(dev_init); 243 module_exit(dev_exit); 244 MODULE_LICENSE("GPL"); 245 MODULE_AUTHOR("cjh");
【2.2】應用程序spa
1 #include <stdio.h> 2 #include <sys/ioctl.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 #include <stdint.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 #include <string.h> 10 #include "../../../driver/spi_fpga/spi_fpga.h" 11 12 int main() 13 { 14 /////////////////////////////////////////////////////////////// 15 16 int fd = open("/dev/spi_fpga", O_RDWR); 17 if(fd < 0) 18 { 19 perror("open device failed\n"); 20 return -1; 21 } 22 int ret = ioctl(fd, SPI_GPIO_IOC__SET_MODE, (int)SPI_GPIO_MODE__0); 23 if(ret < 0) 24 { 25 perror("set mode failed\n"); 26 close(fd); 27 return -2; 28 } 29 ret = ioctl(fd, SPI_GPIO_IOC__SET_LEN, 4); 30 if(ret < 0) 31 { 32 perror("set len failed\n"); 33 close(fd); 34 return -2; 35 } 36 uint8_t buf[4] = {0x2,0x6d,0x3b,0x0};// read reg[0] 37 ret = ioctl(fd, SPI_GPIO_IOC__TRANS, buf); 38 if(ret < 0) 39 { 40 perror("trans failed\n"); 41 close(fd); 42 return -2; 43 } 44 printf("%02x,%02x,%02x,%02x\n",buf[3],buf[2],buf[1],buf[0]); 45 46 close(fd); 47 return 0; 48 }