为了对原来的spi裸驱进行升级,将移植到leon3的ecos版本从2.0升级到3.0,并利用ecos的io系统编写新的spi驱动,以提高io吞吐率,保证线程安全。
Ecos spi驱动作为spi基本的字符驱动进行编写。
1.建立系统目录。
在./ecos-3.0/packages/devs/spi目录下建立driver packagedir。我的目录结构如下:
xiaoyang@xiaoyang leon$ tree -L 5
.
`-- DE2-70
`-- v3_0
|-- cdl
| |-- spi_leon3.cdl
|-- ChangeLog
|-- include
| |-- spi_leon3.h
|-- src
| |-- spi_leon3.c
`-- tests
|-- compile.log
|-- loopback.c
`-- spi_test.c
6 directories, 19 files
2.编写CDL配置脚本
1 ##=============================================================================
2 ##
3 ## spi_leon3.cdl
4 ##
5 ## LEON3-WSN SPI driver configuration options.
6 ##
7 ##=============================================================================
8 #######DESCRIPTIONBEGIN####
9 ##
10 ## Author(s): xiaoyang.yi
11 ## Date: 2012-2-27
12 ## Purpose: Configure leon3-wsn SPI driver.
13 ##
14 ######DESCRIPTIONEND####
15 ##=============================================================================
16
17 cdl_package CYGPKG_DEVS_SPI_LEON3 {
18 display "SPI driver for Leon3"
19 include_dir cyg/io
20 requires CYGPKG_IO
21 compile -library=libextras.a spi_leon3.c
22 description "SPI driver for Leon3"
23
24 cdl_component CYGPKG_DEVS_SPI_LEON3_OPTIONS {
25 display "Compile Options"
26 flavor none
27 no_define
28
29 cdl_option CYGPKG_DEVS_SPI_LEON3_CFLAGS {
30 display "Additional compiler flags"
31 flavor data
32 no_define
33 default_value { "" }
34 description "
35 This option modifies the set of compiler flags for
36 building the spi driver package. These flags
37 are used in addition to the set of global flags."
38 }
39
40 cdl_option CYGDAT_DEVS_SPI_LEON3_NAME {
41 display "Device name for the spi driver"
42 flavor data
43 default_value {"\"/dev/spi\""}
44 description " This option specifies the name of the spi device"
45 }
46
47 cdl_option CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE {
48 display "Debug Message"
49 default_value 0
50 description "
51 This option will enable the debug message outputing if set to 1,
52 will disable the outputing if set to 0."
53 }
54 }
55
56 cdl_component CYGHWR_DEVS_SPI_LEON3_OPTIONS {
57 display "Connection Options"
58 flavor none
59 no_define
60
61 cdl_option CYGNUM_DEVS_SPI_LEON3_EVENT_BUFFER_SIZE {
62 display "Number of events the driver can buffer"
63 flavor data
64 legal_values 1 to 512
65 default_value 32
66 description "
67 This option defines the size of the keypad device internal
68 buffer. The cyg_io_read() function will return as many of these
69 as there is space for in the buffer passed."
70 }
71
72 cdl_option CYGNUM_DEVS_SPI_LEON3_MODE_SELECT {
73 display "SPI Master/Slave Mode Select"
74 flavor data
75 legal_values { "MASTER" "SLAVE" }
76 default_value {"MASTER"}
77 description "
78 This option select Master or Slave mode."
79 }
80 }
81 }
82 # EOF spi_leon3.cdl
在configtool下的效果如下图:
3.编写驱动程序代码.由于本工程原有的裸驱还未加上中断模式,所以ecos spi沿袭之前驱动代码并未提供中断模式供选择。
头文件spi_leon3.h:
1 /*
2 * SPI deriver for ecos on DE2-70
3 * xiaoyang
4 * 2012-2-26 11:03 create it.
5 * 2012-3-1 16:44 test ok.
6 */
7
8 #ifndef CYGONCE_DEVS_SPI_LEON3_H
9 #define CYGONCE_DEVS_SPI_LEON3_H
10
11 /* leon3 bus address*/
12 #define SPI0_BASE 0x80000600
13
14 #define REG32(x) *((volatile unsigned long*)(x))
15
16 /* SPICTL Registers APB Address Offset */
17 #define SPI_CAP 0x0
18 #define SPI_MOD 0x20
19 #define SPI_EVE 0x24
20 #define SPI_MSK 0x28
21 #define SPI_CMD 0x2C
22 #define SPI_TX 0x30
23 #define SPI_RX 0x34
24 #define SPI_SLV 0x38
25 /* Bit Definition of SPICTL Capability Register */
26 #define SPI_CAP_REV 0x7F
27 #define SPI_CAP_FDEPTH 0xFF00
28 #define SPI_CAP_SSEN 0x10000
29 #define SPI_CAP_ASELA 0x20000
30 #define SPI_CAP_AMODE 0x40000
31 #define SPI_CAP_TWEN 0x80000
32 #define SPI_CAP_MAXWLEN 0xF00000
33 #define SPI_CAP_SSSZ 0xFF000000
34 /* Bit Definition of SPICTL Mode Register */
35 #define SPI_MOD_TAC 0x10
36 #define SPI_MOD_ASELDEL 0x60
37 #define SPI_MOD_CG 0x780
38 #define SPI_MOD_OD 0x1000
39 #define SPI_MOD_FACT 0x2000
40 #define SPI_MOD_ASEL 0x4000
41 #define SPI_MOD_TW 0x8000
42 #define SPI_MOD_PM 0xF0000 /* Prescale Module*/
43 #define SPI_MOD_LEN 0xF00000
44 #define SPI_MOD_EN 0x1000000
45 #define SPI_MOD_MS 0x2000000 /* Master/Slave */
46 #define SPI_MOD_REV 0x4000000
47 #define SPI_MOD_DIV16 0x8000000
48 #define SPI_MOD_CPHA 0x10000000
49 #define SPI_MOD_CPOL 0x20000000
50 #define SPI_MOD_LOOP 0x40000000
51 #define SPI_MOD_AMEN 0x80000000
52 /* Bit Definition of SPICTL Event Register */
53 #define SPI_EVE_NF 0x100
54 #define SPI_EVE_NE 0x200
55 #define SPI_EVE_MME 0x400
56 #define SPI_EVE_UR 0x800
57 #define SPI_EVE_OV 0x1000
58 #define SPI_EVE_LT 0x4000
59 #define SPI_EVE_TIP 0x80000000 /* Transfer in Progress */
60 /* Bit Definition of SPICTL Mask Register */
61 #define SPI_MSK_NFE 0x100
62 #define SPI_MSK_NEE 0x200
63 #define SPI_MSK_MMEE 0x400
64 #define SPI_MSK_UNE 0x800
65 #define SPI_MSK_OVE 0x1000
66 #define SPI_MSK_LTE 0x4000
67 #define SPI_MSK_TIPE 0x80000000
68 /* Bit Definition of SPICTL Command Register */
69 #define SPI_CMD_LST 0x400000
70 /* Bit Definition of SPICTL Slave Select Register */
71 #define SPI_SLV_SSSZ 1
72 #define SPI_SLV_SLVSEL (1<<SPI_SLV_SSSZ)-1
73
74 /* Some useful routines */
75 #define SLV_SELECT() REG32(SPI_BASE+SPI_SLV) &= ~SPI_SLV_SLVSEL
76 #define SLV_DESELECT() REG32(SPI_BASE+SPI_SLV) |= SPI_SLV_SLVSEL
77
78 #endif // CYGONCE_DEVS_SPI_CORTEXM_LEON3_H
驱动主文件spi_leon3.c:
1 /*
2 * SPI deriver for ecos on DE2-70
3 * xiaoyang
4 * 2012-2-26 11:03 create it.
5 * 2012-3-1 16:44 test ok.
6 */
7
8 #include <pkgconf/hal.h> /*hal 的宏头文件,由系统自动生成*/
9 #include <pkgconf/devs_spi_leon3.h> /* spi 驱动 cdl 文件宏头文件,由系统自动生成*/
10 #include <cyg/infra/cyg_type.h> /* 定义类型*/
11 #include <cyg/hal/hal_intr.h> /* 定义中断相关宏*/
12 #include <cyg/hal/drv_api.h> /* 驱动程序头文件*/
13 #include <cyg/error/codes.h> /* 定义错误常量,如 ENOERR*/
14
15 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
16 #include <cyg/infra/testcase.h> /* 测试宏定义,如 CYG_TEST_CHECK*/
17 #include <cyg/infra/diag.h> /* diag 函数声明*/
18 #include <stdio.h> /* 调试函数如 printf 等声明*/
19 #endif
20
21 #include <cyg/io/devtab.h> /* 设备 I/O 入口表定义及声明*/
22 #include <cyg/io/spi_leon3.h> /* 定义 LEON3 的 SPI 模块相关常量,这里含 key*/
23
24 //-----------------------------------------------------------------------------------//
25
26 #define SPI0_REV 1 /* Reverse data*/
27
28 //-----------------------------------------------------------------------------------//
29 // Functions in this module
30 static Cyg_ErrNo spi_write (cyg_io_handle_t handle, void *buffer, cyg_uint32 * len);
31 static Cyg_ErrNo spi_read (cyg_io_handle_t handle, void *buffer, cyg_uint32 * len);
32 static Cyg_ErrNo spi_set_config (cyg_io_handle_t handle, cyg_uint32 key, const void *buffer, cyg_uint32 * len);
33 static Cyg_ErrNo spi_get_config (cyg_io_handle_t handle, cyg_uint32 key, const void *buffer, cyg_uint32 * len);
34 static bool spi_init (struct cyg_devtab_entry *tab);
35 static Cyg_ErrNo spi_lookup (struct cyg_devtab_entry **tab, struct cyg_devtab_entry *st, const char *name);
36
37 /*old interface*/
38 static void old_spi_init(unsigned long spi_base);
39 static cyg_uint8 old_spi_xmit8(unsigned long spi_base, cyg_uint8 val);
40
41 /*xiaoyang add*/
42 static cyg_bool _SPIDrv_is_open;
43 static cyg_uint8 TxFlag,RxFlag;
44 static cyg_sem_t sem_spi_data;
45
46 //-----------------------------------------------------------------------------------//
47 CHAR_DEVIO_TABLE (
48 leon3_spi_handlers, // SPI 设备 I/O 函数表句柄
49 spi_write, // SPI 设备写函数
50 spi_read, // SPI 设备读函数
51 NULL, //
52 spi_get_config, // SPI 读设备设置状态函数
53 spi_set_config // SPI 设备设置函数
54 );
55
56 CHAR_DEVTAB_ENTRY (
57 leon3_spi_device, // SPI 设备表入口句柄
58 CYGDAT_DEVS_SPI_LEON3_NAME, // 设备名,在 cdl 文件中进行宏定义
59 NULL, //
60 &leon3_spi_handlers, // SPI 设备 I/O 函数表句柄指针
61 spi_init, // SPI 初始化函数
62 spi_lookup, // SPI 设备查找函数
63 NULL);
64
65 //-----------------------------------------------------------------------------------//
66 static cyg_uint32 spi_INTService (cyg_uint32 vector, CYG_ADDRWORD data)
67 {
68 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
69 /* check is ISR installed ok*/
70 //CYG_TEST_CHECK (ISR_DATA == data, "Bad data passed to ISR");
71 /* check IRQ43 INT*/
72 CYG_TEST_CHECK (43 == vector, "Bad vector passed to ISR");
73 printf ("Debug - spi Int Services\n");
74 #endif
75
76 /* handling IRQ INT*/
77 HAL_INTERRUPT_ACKNOWLEDGE (vector);
78 /* if SND*/
79 if (TxFlag == 1)
80 {
81 /* if SND_INT*/
82 if ( 0)
83 {
84
85 }
86 }
87 /* if REV*/
88 if (RxFlag == 1)
89 {
90 /* if RCV_INT*/
91 if (0)
92 {
93
94 }
95 }
96 /* ISR return */
97 return CYG_ISR_HANDLED;
98 }
99
100 static Cyg_ErrNo spi_write (cyg_io_handle_t handle, void *buffer, cyg_uint32 * len)
101 {
102 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
103 printf ("Debug - spi write data\n");
104 #endif
105
106 cyg_uint8 *bp = (cyg_uint8 *)buffer;
107 int i = 0;
108
109 /*wait semaphore*/
110 cyg_semaphore_wait(&sem_spi_data);
111
112 for(i = 0; i < (*len); i++){
113 old_spi_xmit8(SPI0_BASE,bp[i]);
114 }
115
116 /*release semaphore*/
117 cyg_semaphore_post(&sem_spi_data);
118
119 return ENOERR;
120 }
121
122 /*
123 * handle:
124 * buffer: data
125 * len: count byte of data to read
126 */
127 static Cyg_ErrNo spi_read (cyg_io_handle_t handle, void *buffer, cyg_uint32 * len)
128 {
129 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
130 printf ("Debug - spi read data\n");
131 #endif
132
133 cyg_uint8 *bp = (cyg_uint8 *)buffer;
134 int i = 0;
135
136 /*wait semaphore*/
137 cyg_semaphore_wait(&sem_spi_data);
138
139 for(i = 0; i < (*len); i++){
140 bp[i] = old_spi_xmit8(SPI0_BASE,0);
141 }
142
143 /*release semaphore*/
144 cyg_semaphore_post(&sem_spi_data);
145 return ENOERR;
146 }
147
148
149 /*
150 * handle:
151 * buffer: data
152 * len: count byte of data to write
153 */
154 static Cyg_ErrNo spi_set_config (cyg_io_handle_t handle, cyg_uint32 key, const void *buffer, cyg_uint32 * len)
155 {
156 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
157 printf ("Debug - spi Set Config\n");
158 #endif
159
160 return ENOERR;
161 }
162
163 static Cyg_ErrNo spi_get_config (cyg_io_handle_t handle, cyg_uint32 key, const void *buffer, cyg_uint32 * len)
164 {
165 return ENOERR;
166 }
167
168 static bool spi_init (struct cyg_devtab_entry *tab)
169 {
170 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
171 printf ("Debug - spi init\n");
172 #endif
173
174 /*old spi init*/
175 old_spi_init(SPI0_BASE);
176
177 /* init a semaphore*/
178 cyg_semaphore_init(&sem_spi_data,0);
179 /*
180 * WARNNING:
181 * release semaphore,you should do it for waking up the thread
182 * who uses the semaphore.
183 */
184 cyg_semaphore_post(&sem_spi_data);
185 return true;
186 }
187 /*
188 *
189 */
190 static Cyg_ErrNo spi_lookup (struct cyg_devtab_entry **tab, struct cyg_devtab_entry *st, const char *name)
191 {
192 #if CYGNUM_DEVS_SPI_LEON3_DEBUG_MODE == 1
193 printf ("Debug - spi Lookup\n");
194 #endif
195 return ENOERR;
196 }
197
198
199 //-----------------------------------------------------------------------------------//
200 /*old complete*/
201 /******************************************************************
202 * Initialize the SPI Controller
203 *
204 *****************************************************************/
205 void old_spi_init(unsigned long spi_base) {
206 REG32(spi_base+SPI_CAP) = 0x01018002;
207 /* Configure the capability register */
208 /* SPI_CAP_FDEPTH = 0x80 => Support FIFO size = 128 */
209 /* SPI_CAP_SSEN = 1 */
210 /* SPI_CAP_MAXWLEN = 0x0 => Support 32-bit length */
211 /* SPI_CAP_SSSZ = 0x01 */
212
213 #if SPI0_REV
214 REG32(spi_base+SPI_MOD) |= 0x06740000;
215 /* Configure the mode register */
216 /* SPI_MOD_FACT = 0*/
217 /* SPI_MOD_PM = 4 */
218 /* SPI_MOD_LEN = 7 */
219 /* SPI_MOD_EN = 0 */
220 /* SPI_MOD_MS = 1 */
221 /* SPI_MOD_REV = 0 */
222 /* SPI_MOD_DIV16 = 0 */
223 /* SPI_MOD_CPHA = 0 */
224 /* SPI_MOD_CPOL = 0 */
225 /* SPI_MOD_REV = 1 */ /* MSB transmitted first */
226 // REG32(spi_base+SPI_MOD) |= SPI_MOD_CPOL;
227 // REG32(spi_base+SPI_MOD) |= SPI_MOD_CPHA;
228 #else //SPI_MOD_REV = 0, LSB transmitted first
229 REG32(spi_base+SPI_MOD) |= 0x02740000;
230 #endif // REV
231 REG32(spi_base+SPI_MSK) = 0x0; /* Disable all interrupts */
232 REG32(spi_base+SPI_MOD) |= SPI_MOD_EN; /* Activate Core */
233 }
234
235 /********************************************************************
236 * SPI TX and RX
237 *
238 *******************************************************************/
239 cyg_uint8 old_spi_xmit8(unsigned long spi_base,cyg_uint8 val) {
240 cyg_uint32 reg32;
241 /* Wait for room */
242 while(!(REG32(spi_base+SPI_EVE)&SPI_EVE_NF));
243
244 #if SPI0_REV
245 REG32(spi_base+SPI_TX) = val<<24&0xFF000000;
246 #else
247 REG32(spi_base+SPI_TX) = val;
248 #endif // REV
249 //while(!(REG32(spi_base+SPI_EVE)&SPI_EVE_NE)); /* Wait for transmitting over */
250 //while(!((REG32(spi_base+SPI_EVE)&SPI_EVE_LT)));
251 while((REG32(spi_base+SPI_EVE)&SPI_EVE_TIP));
252 reg32 = REG32(spi_base+SPI_RX);
253 //printf("1st: 0x%x\n",reg32);
254
255 #if SPI0_REV
256 return (cyg_uint8)((reg32>>16)&0xFF);
257 #else
258 return (cyg_uint8)((reg32>>8)&0xFF);
259 #endif // REV
260 }
261
262 cyg_uint16 old_spi_xmit16(unsigned long spi_base, cyg_uint16 val)
263 {
264 while(!(REG32(spi_base+SPI_EVE)&SPI_EVE_NF));
265 #if SPI0_REV
266 REG32(spi_base+SPI_TX) = val<<16&0xFFFF0000;
267 #else
268 REG32(spi_base+SPI_TX) = val;
269 #endif // REV
270 while((REG32(spi_base+SPI_EVE)&SPI_EVE_TIP));
271 cyg_uint32 reg32 = REG32(spi_base+SPI_RX);
272 //printf("back32: 0x%8x\n",reg32);
273 #if SPI0_REV
274 return (cyg_uint16)((reg32>>16)&0xFFFF);
275 #else
276 return (cyg_uint16)(reg32&0xFFFF);
277 #endif // REV
278 }
279
280 /*******************************************************************
281 * Reconfigure SPI Mode Register
282 *
283 ******************************************************************/
284 cyg_uint8 old_spi_reconfig(unsigned long spi_base,cyg_uint32 mask, cyg_uint32 val)
285 {
286 cyg_uint32 mod;
287 if(REG32(spi_base+SPI_EVE)&SPI_EVE_TIP) {
288 return -1;
289 }
290 /* Disable the SPI core */
291 REG32(spi_base+SPI_MOD) &= (~SPI_MOD_EN);
292
293 mod = REG32(spi_base+SPI_MOD);
294 mod = (mod & ~mask) | val;
295 REG32(spi_base+SPI_MOD) = mod;
296
297 REG32(spi_base+SPI_MOD) |= SPI_MOD_EN;
298 return 0;
299 }
300
301
302 //-----------------------------------------------------------------------------------//
303 //end of file//
304 //-----------------------------------------------------------------------------------//
(如果想使用原生的spi驱动包可以使用ecosconfig工具建立ecc编译文件,./ecosconfig add CYGPKG_IO_SPI命令加入包)
最后使用configtool将spi模块加载进去进行编译即可使用此驱动。
下面是测试代码,即使用spi驱动的方法:
1 // 定义 SPI 线程的句柄
2 cyg_io_handle_t hDrvSPI;
3
4 // 通过 SPI 线程进行发送和接收数据
5 void spi_thread(cyg_addrword_t data)
6 {
7 cyg_uint32 len = 1;
8 cyg_uint32 RxData[1];
9 cyg_uint32 TxData[1];
10 TxData[0]=66;
11 if (ENOERR != cyg_io_lookup("/dev/spi", &hDrvSPI))
12 {
13 CYG_TEST_FAIL_FINISH("Error opening /dev/spi");
14 }
15 printf("Open /dev/spi OK\n");
16 while(true)
17 {
18 len = 1;
19 // 通过 SPI 线程进行发送和接收数据
20 if(ENOERR != cyg_io_write(hDrvSPI, TxData, &len))
21 {
22 CYG_TEST_FINISH("Error write /dev/spi");
23 }
24 printf("SPI TxNum = %d\n",len); // 返回实际发送数据量
25 if(len != 0)
26 {
27 printf("SPI TxData = %d\n", TxData[0]);
28 }
29 // 调用 cyg_io_ read 接收数据
30 if(ENOERR != cyg_io_read(hDrvSPI, RxData, &len))
31 {
32 CYG_TEST_FINISH("Error Read /dev/spi");
33 }
34 if(len != 0)
35 {
36 printf("SPI RxData = %d\n", RxData[0]);
37 }
38 // 线程睡眠
39 cyg_thread_delay(10);
40 }
41 }
spi驱动代码详情可在git-hub中找到:https://github.com/yixiaoyang/leon-wsn/tree/master/driver