OSDN Git Service

0c4a856adf9536754f6faa7ca7da73184d567efc
[nxt-jsp/etrobo-atk.git] / nxtOSEK / lejos_nxj / src / nxtvm / platform / nxt / twi.c
1
2 #include "mytypes.h"
3 #include "twi.h"
4 #include "interrupts.h"
5 #include "AT91SAM7.h"
6
7 #include "systick.h"
8
9 #include "byte_fifo.h"
10
11 #include "aic.h"
12
13
14
15 extern void twi_isr_entry(void);
16
17
18 static enum {
19   TWI_UNINITIALISED = 0,
20   TWI_IDLE,
21   TWI_TX_BUSY,
22   TWI_TX_DONE,
23   TWI_RX_BUSY,
24   TWI_RX_DONE,
25   TWI_FAILED
26 } twi_state;
27
28 static U32 twi_pending;
29 static U8 *twi_ptr;
30
31 static struct {
32   U32 rx_done;
33   U32 tx_done;
34   U32 bytes_tx;
35   U32 bytes_rx;
36   U32 unre;
37   U32 ovre;
38   U32 nack;
39 } twi_stats;
40
41
42
43
44 int
45 twi_busy(void)
46 {
47   return (twi_state == TWI_TX_BUSY || twi_state == TWI_RX_BUSY);
48 }
49
50 int
51 twi_ok(void)
52 {
53   return (twi_state >= TWI_IDLE && twi_state <= TWI_RX_DONE);
54 }
55
56 void
57 twi_isr_C(void)
58 {
59   U32 status = *AT91C_TWI_SR;
60
61   if ((status & AT91C_TWI_RXRDY) && twi_state == TWI_RX_BUSY) {
62
63
64     if (twi_pending) {
65       twi_stats.bytes_rx++;
66       *twi_ptr = *AT91C_TWI_RHR;
67       twi_ptr++;
68       twi_pending--;
69       if (twi_pending == 1) {
70         /* second last byte -- issue a stop on the next byte */
71         *AT91C_TWI_CR = AT91C_TWI_STOP;
72       }
73       if (!twi_pending) {
74         twi_stats.rx_done++;
75         twi_state = TWI_RX_DONE;
76       }
77     }
78
79   }
80
81   if ((status & AT91C_TWI_TXRDY) && twi_state == TWI_TX_BUSY) {
82     if (twi_pending) {
83       /* Still Stuff to send */
84       *AT91C_TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_START;
85       if (twi_pending == 1) {
86         *AT91C_TWI_CR = AT91C_TWI_STOP;
87       }
88       *AT91C_TWI_THR = *twi_ptr;
89       twi_stats.bytes_tx++;
90
91       twi_ptr++;
92       twi_pending--;
93
94     } else {
95       /* everything has been sent */
96       twi_state = TWI_TX_DONE;
97       *AT91C_TWI_IDR = ~0;
98       twi_stats.tx_done++;
99     }
100   }
101
102   if (status & AT91C_TWI_OVRE) {
103     /* */
104     twi_stats.ovre++;
105     *AT91C_TWI_CR = AT91C_TWI_STOP;
106     *AT91C_TWI_IDR = ~0;
107     twi_state = TWI_FAILED;
108
109   }
110
111   if (status & AT91C_TWI_UNRE) {
112     /* */
113     twi_stats.unre++;
114     *AT91C_TWI_IDR = ~0;
115     twi_state = TWI_FAILED;
116   }
117
118   if (status & AT91C_TWI_NACK) {
119     /* */
120     twi_stats.nack++;
121     *AT91C_TWI_IDR = ~0;
122     twi_state = TWI_UNINITIALISED;
123   }
124 }
125
126
127
128 void
129 twi_reset(void)
130 {
131   U32 clocks = 9;
132
133   *AT91C_TWI_IDR = ~0;
134
135   *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_PIOA) |   /* Need PIO too */
136     (1 << AT91C_PERIPHERAL_ID_TWI);     /* TWI clock domain */
137
138   /* Set up pin as an IO pin for clocking till clean */
139   *AT91C_PIOA_MDER = (1 << 3) | (1 << 4);
140   *AT91C_PIOA_PER = (1 << 3) | (1 << 4);
141   *AT91C_PIOA_ODR = (1 << 3);
142   *AT91C_PIOA_OER = (1 << 4);
143
144   while (clocks > 0 && !(*AT91C_PIOA_PDSR & (1 << 3))) {
145
146     *AT91C_PIOA_CODR = (1 << 4);
147     systick_wait_ns(1500);
148     *AT91C_PIOA_SODR = (1 << 4);
149     systick_wait_ns(1500);
150     clocks--;
151   }
152
153   *AT91C_PIOA_PDR = (1 << 3) | (1 << 4);
154   *AT91C_PIOA_ASR = (1 << 3) | (1 << 4);
155
156   *AT91C_TWI_CR = 0x88;         /* Disable & reset */
157
158   *AT91C_TWI_CWGR = 0x020f0f;   /* Set for 380kHz */
159   *AT91C_TWI_CR = 0x04;         /* Enable as master */
160 }
161
162 int
163 twi_init(void)
164 {
165   int i_state;
166
167   i_state = interrupts_get_and_disable();
168
169   /* Todo: set up interrupt */
170   *AT91C_TWI_IDR = ~0;          /* Disable all interrupt sources */
171   aic_mask_off(AT91C_PERIPHERAL_ID_TWI);
172   aic_set_vector(AT91C_PERIPHERAL_ID_TWI, AIC_INT_LEVEL_ABOVE_NORMAL,
173                  twi_isr_entry);
174   aic_mask_on(AT91C_PERIPHERAL_ID_TWI);
175
176
177   twi_reset();
178
179   /* Init peripheral */
180
181   twi_state = TWI_IDLE;
182
183   if (i_state)
184     interrupts_enable();
185
186   return 1;
187 }
188
189
190
191 void
192 twi_start_read(U32 dev_addr, U32 int_addr_bytes, U32 int_addr, U8 *data,
193                U32 nBytes)
194 {
195   U32 mode =
196     ((dev_addr & 0x7f) << 16) | ((int_addr_bytes & 3) << 8) | (1 << 12);
197   U32 dummy;
198
199   if (!twi_busy()) {
200
201     twi_state = TWI_RX_BUSY;
202     *AT91C_TWI_IDR = ~0;        /* Disable all interrupts */
203     twi_ptr = data;
204     twi_pending = nBytes;
205     dummy = *AT91C_TWI_SR;
206     dummy = *AT91C_TWI_RHR;
207 //      *AT91C_AIC_ICCR = ( 1<< AT91C_PERIPHERAL_ID_TWI);
208     *AT91C_TWI_MMR = mode;
209     *AT91C_TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN;
210 //      dummy = *AT91C_TWI_SR;
211     *AT91C_TWI_IER = 0x01C2;
212   }
213
214 }
215
216 void
217 twi_start_write(U32 dev_addr, U32 int_addr_bytes, U32 int_addr,
218                 const U8 *data, U32 nBytes)
219 {
220   U32 mode = ((dev_addr & 0x7f) << 16) | ((int_addr_bytes & 3) << 8);
221
222   if (!twi_busy()) {
223     twi_state = TWI_TX_BUSY;
224     *AT91C_TWI_IDR = ~0;        /* Disable all interrupts */
225     twi_ptr = data;
226     twi_pending = nBytes;
227
228     *AT91C_TWI_MMR = mode;
229     *AT91C_TWI_CR = AT91C_TWI_START | AT91C_TWI_MSEN;
230     *AT91C_TWI_IER = 0x1C4;
231   }
232
233 }