OSDN Git Service

Update lejos_osek to nxtOSEK_v205b0.zip
[nxt-jsp/etrobo-atk.git] / nxtOSEK / lejos_nxj / src / nxtvm / platform / nxt / nxt_spi.c
1
2 #include "nxt_spi.h"
3 #include "interrupts.h"
4 #include "AT91SAM7.h"
5
6 #include "byte_fifo.h"
7
8 #include "aic.h"
9
10
11 /*
12  * Note that this is not a normal SPI interface, 
13  * it is a bodged version as used by the NXT's 
14  * display.
15  *
16  * The display does not use MISO because you can
17  * only write to it in serial mode.
18  *
19  * Instead, the MISO pin is not used by the SPI
20  * and is instead driven as a PIO pin for controlling CD.
21  *
22  * Addional notes from Andy Shaw
23  * The following code now contains the capability to perform display
24  * updates using dma, This code was inspired by the nxos lcd/spi code
25  * (Thanks guys). More details of nxos can be found at:
26  * http://nxt.natulte.net/nxos/trac
27  *
28  */
29
30
31 #define CS_PIN  (1<<10)
32 #define CD_PIN  (1<<12)
33 const U8 *display = (U8 *) 0;
34 volatile U8 dirty = 0;
35 volatile U8 page = 0;
36 volatile const U8 *data = (U8 *) 0;
37 U8 mode = 0xff;
38
39 extern void spi_isr_entry(void);
40
41 static void spi_set_mode(U8 m)
42 {
43   U32 status;
44
45   /* nothing to do if we are already in the correct mode */
46   if (m == mode) return;
47   
48   /* Wait until all bytes have been sent */
49   do {
50     status = *AT91C_SPI_SR;
51   } while (!(status & 0x200));
52   /* Set command or data mode */
53   if (m)
54     *AT91C_PIOA_SODR = CD_PIN;
55   else
56     *AT91C_PIOA_CODR = CD_PIN;
57   /* remember the current mode */
58   mode = m;
59 }
60
61
62 void
63 spi_isr_C(void)
64 {
65   if (page == 0)
66   {
67     /* Check to see if we have data to display */
68     if (dirty != 0)
69     {
70       data = display;
71       dirty = 0;
72     }
73     else
74     {
75       /* No so turn things off. It will get re-set if we ever have anything
76          to display
77       */
78       *AT91C_SPI_IDR = AT91C_SPI_ENDTX;
79       return;
80     }
81   }
82   /* Make sure we are in data mode */
83   spi_set_mode(1);
84   /* now do the transfer. We make use of the auto-wrap function so simply
85    * need to send 8*132 bytes to get back to where we started. However the
86    * display buffer is structured as series of 100 byte lines, so we need to
87    * get tricky. I've made the display one line longer (9 lines) and so when we
88    * send the data we send 100 bytes from the actual line plus 32 padding bytes
89    * (that are not actually seen), from the next line. The extra line means
90    * that this is safe to do. If we can redefine the display as a 8*132 then
91    * we could just use a single dma transfer (instead of 8, 132 byte ones).
92    * However I'm not sure if this would be safe.
93    */
94   *AT91C_SPI_TNPR = (U32) data;
95   *AT91C_SPI_TNCR = 132;
96   page = (page + 1) % 8;
97   data += 100;
98 }
99
100
101 void
102 nxt_spi_init(void)
103 {
104   int i_state = interrupts_get_and_disable();
105 #define OSC 48054805
106 #define SPI_BITRATE 2000000
107
108   *AT91C_PMC_PCER  =  (1L << AT91C_ID_SPI);       /* Enable MCK clock     */
109   *AT91C_PIOA_PER = AT91C_PIO_PA12;/*EnableA0onPA12*/
110   *AT91C_PIOA_OER = AT91C_PIO_PA12;
111   *AT91C_PIOA_CODR = AT91C_PIO_PA12;
112   *AT91C_PIOA_PDR = AT91C_PA14_SPCK;/*EnableSPCKonPA14*/
113   *AT91C_PIOA_ASR = AT91C_PA14_SPCK;
114   *AT91C_PIOA_ODR = AT91C_PA14_SPCK;
115   *AT91C_PIOA_OWER = AT91C_PA14_SPCK;
116   *AT91C_PIOA_MDDR = AT91C_PA14_SPCK;
117   *AT91C_PIOA_PPUDR = AT91C_PA14_SPCK;
118   *AT91C_PIOA_IFDR = AT91C_PA14_SPCK;
119   *AT91C_PIOA_CODR = AT91C_PA14_SPCK;
120   *AT91C_PIOA_IDR = AT91C_PA14_SPCK;
121   *AT91C_PIOA_PDR = AT91C_PA13_MOSI;/*EnablemosionPA13*/
122   *AT91C_PIOA_ASR = AT91C_PA13_MOSI;
123   *AT91C_PIOA_ODR = AT91C_PA13_MOSI;
124   *AT91C_PIOA_OWER = AT91C_PA13_MOSI;
125   *AT91C_PIOA_MDDR = AT91C_PA13_MOSI;
126   *AT91C_PIOA_PPUDR = AT91C_PA13_MOSI;
127   *AT91C_PIOA_IFDR = AT91C_PA13_MOSI;
128   *AT91C_PIOA_CODR = AT91C_PA13_MOSI;
129   *AT91C_PIOA_IDR = AT91C_PA13_MOSI;
130   *AT91C_PIOA_PDR = AT91C_PA10_NPCS2;/*Enablenpcs0onPA10*/
131   *AT91C_PIOA_BSR = AT91C_PA10_NPCS2;
132   *AT91C_PIOA_ODR = AT91C_PA10_NPCS2;
133   *AT91C_PIOA_OWER = AT91C_PA10_NPCS2;
134   *AT91C_PIOA_MDDR = AT91C_PA10_NPCS2;
135   *AT91C_PIOA_PPUDR = AT91C_PA10_NPCS2;
136   *AT91C_PIOA_IFDR = AT91C_PA10_NPCS2;
137   *AT91C_PIOA_CODR = AT91C_PA10_NPCS2;
138   *AT91C_PIOA_IDR = AT91C_PA10_NPCS2;
139   *AT91C_SPI_CR = AT91C_SPI_SWRST;/*Softreset*/
140   *AT91C_SPI_CR = AT91C_SPI_SPIEN;/*Enablespi*/
141   *AT91C_SPI_MR = AT91C_SPI_MSTR|AT91C_SPI_MODFDIS | (0xB<<16);
142   AT91C_SPI_CSR[2] = ((OSC/SPI_BITRATE)<<8) | AT91C_SPI_CPOL;
143
144   /* Set mode to unknown */
145   mode = 0xff;
146
147   /* Set up safe dma refresh state */
148   data = display = (U8 *) 0;
149   dirty = 0;
150   page = 0;
151
152   /* Install the interrupt handler */
153   aic_mask_off(AT91C_PERIPHERAL_ID_SPI);
154   aic_set_vector(AT91C_PERIPHERAL_ID_SPI, AIC_INT_LEVEL_NORMAL, (U32)spi_isr_entry);
155   aic_mask_on(AT91C_PERIPHERAL_ID_SPI);
156   *AT91C_SPI_PTCR = AT91C_PDC_TXTEN;
157
158   if (i_state)
159     interrupts_enable();
160
161 }
162
163 void
164 nxt_spi_write(U32 CD, const U8 *data, U32 nBytes)
165 {
166   U32 status;
167   U32 cd_mask = (CD ? 0x100 : 0);
168
169   spi_set_mode(CD);
170   while (nBytes) {
171     *AT91C_SPI_TDR = (*data | cd_mask);
172     data++;
173     nBytes--;
174     /* Wait until byte sent */
175     do {
176       status = *AT91C_SPI_SR;
177     } while (!(status & 0x200));
178
179   }
180 }
181
182 void
183 nxt_spi_set_display(const U8 *disp)
184 {
185   /* Set the display buffer to be used for dma refresh.
186    * it is really only safe to set the display once. Should probably
187    * sort this out so that it is set separately from requesting a refresh
188    */
189   if (!display) display = disp;
190 }
191
192 void
193 nxt_spi_refresh(void)
194 {
195   /* Request the start of a dma refresh of the display 
196    */
197   // If the display is not set nothing to do.
198   if (!display) return;
199   // Say we have changes
200   dirty = 1;
201   // Start the DMA refresh
202   *AT91C_SPI_IER = AT91C_SPI_ENDTX;
203 }