Hanna
Sourcecode Kontrollplatine
usartx.c
gehe zur Dokumentation dieser Datei
1 
23 #include <avr/io.h>
24 #include <avr/interrupt.h>
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <util/delay.h>
28 
29 /*
30  * This file must create the FILE objects, so define OWNER here.
31  */
32 #define OWNER
33 
34 #include "usartx.h"
35 
36 #ifndef IN_FILENO
37 #define IN_FILENO 0
38 #define OUT_FILENO 1
39 #define ERR_FILENO 2
40 #endif
41 
42 #ifndef NUM_USARTS
43 #define NUM_USARTS 7
44 #endif
45 
46 /*
47  * Create an array of pointers to the various USART I/O registers.
48  */
49 static USART_t *usart[NUM_USARTS] = { &USARTC0, &USARTC1, &USARTD0, &USARTD1, &USARTE0, &USARTF0 };
50 
51 /*
52  * Prototypes for the getchar and putchar functions for any USART.
53  */
54 static int USART_putchar ( char c, FILE *stream ) __attribute__((noinline));
55 static int USART_getchar ( FILE *stream ) __attribute__((noinline));
56 
57 /*
58  * Define the low-level FILEs used for stream I/O by the USARTs.
59  *
60  * These FILEs can be used to change the behavior of stdin, stdout,
61  * and stderr. For example:
62  *
63  * stdin = &usartin;
64  * stdout = &usartout;
65  * stderr = &usartout;
66  *
67  * NOTE: In keeping with the comments in avr/stdio.h, the following FILE
68  * implementations do NOT provide stream.size, stream.buf, stream.unget,
69  * stream.flags, or stream.len! If you need support for these features,
70  * you must provide them in code outside of any of the USART functions
71  * defined in this library!
72  *
73  */
74 FILE usart_out = FDEV_SETUP_STREAM(USART_putchar, NULL, _FDEV_SETUP_WRITE);
75 FILE usartout = FDEV_SETUP_STREAM(USART_putchar, NULL, _FDEV_SETUP_WRITE);
76 FILE usartin = FDEV_SETUP_STREAM(NULL, USART_getchar, _FDEV_SETUP_READ);
77 
78 /*
79  * Define variables for holding the identifier for the USART currently connected
80  * to a standard I/O stream.
81  */
82 static int usartsel_in = eUSARTC0; // defaults to USARTC0
83 static int usartsel_out = eUSARTC0; // defaults to USARTC0
84 static int usartsel_err = eUSARTC0; // defaults to USARTC0
85 
86 #define QUEUE_SIZE 64 /* MUST BE A POWER OF 2!! */
87 
88 /*
89  * Define in and out pointers (actually, indices) for each of the queues associated
90  * with a USART receiver. inptr[] holds the index into the queue where the next
91  * received character will be added. outptr[] holds the index into the queue where
92  * the next character will be extracted for passing to a calling program.
93  */
94 static volatile unsigned char inptr[NUM_USARTS] = { 0, 0, 0, 0, 0, 0 }; // index for adding chars to queue
95 static volatile unsigned char outptr[NUM_USARTS] = { 0, 0, 0, 0, 0, 0 }; // index for pulling chars from queue
96 
97 /*
98  * Define queues for handling chars received by each USART.
99  */
100 static volatile unsigned char queue[NUM_USARTS][QUEUE_SIZE];
101 
102 /*
103  * Local functions
104  */
105 static void _rxcisr ( int usartnum );
106 
107 /*
108  * USART_Init() Initialise hardware USARTs
109  *
110  * This code configures the USARTs for selected baud rate, eight data bits,
111  * no parity, one stop bit. It also enables the USARTs' transmitter and
112  * receiver, and enables receive interrupts.
113  */
114 void USART_Init ( uint8_t usartnum, uint8_t bauda, uint8_t baudb )
115 {
116  stdout = &usartout;
117  USART_t *pusart;
118 
119  if ( usartnum >= NUM_USARTS ) return; // ignore if out of range
120 
121  pusart = usart[usartnum]; // point to selected USART I/O block
122  switch (usartnum)
123  // based on selected USART...
124  {
125  case eUSARTC0: // USARTC0
126  PORTC_OUTSET |= PIN3_bm; // force TXD high
127  PORTC_DIRSET |= PIN3_bm; // TXD is output
128  PORTC_OUTCLR = PIN2_bm;
129  PORTC_DIRCLR = PIN2_bm; //PC6 as RX
130  PORTC_PIN3CTRL |= 0x18; // pin is pulled high
131  break;
132 
133  case eUSARTC1: // USARTC1
134  PORTC_OUTSET |= PIN7_bm; // force TXD high
135  PORTC_DIRSET |= PIN7_bm; // TXD is output
136  PORTC_PIN7CTRL |= 0x18; // pin is pulled high
137  break;
138 
139  case eUSARTD0: // USARTD0
140  PORTD_OUTSET |= PIN3_bm; // force TXD high
141  PORTD_DIRSET |= PIN3_bm; // TXD is output
142  PORTD_PIN3CTRL |= 0x18; // pin is pulled high
143  break;
144 
145  case eUSARTD1: // USARTD1
146  PORTD_OUTSET |= PIN7_bm; // force TXD high
147  PORTD_DIRSET |= PIN7_bm; // TXD is output
148  PORTD_PIN7CTRL |= 0x18; // pin is pulled high
149  break;
150 
151  case eUSARTE0: // USARTE0
152  PORTE_OUTSET |= PIN3_bm; // force TXD high
153  PORTE_DIRSET |= PIN3_bm; // TXD is output
154  PORTE_PIN3CTRL |= 0x18; // pin is pulled high
155  break;
156 
157  case eUSARTF0: // USARTF0
158  PORTF_OUTSET |= PIN3_bm; // force TXD high
159  PORTF_DIRSET |= PIN3_bm; // TXD is output
160  PORTF_OUTCLR = PIN2_bm;
161  PORTF_DIRCLR = PIN2_bm; // PF2 as RX
162  PORTF_PIN3CTRL |= 0x18; // pin is pulled high
163  break;
164 
165  default: // should never happen!
166  break;
167  }
168 
169  pusart->CTRLA = USART_RXCINTLVL_HI_gc; // enable RX interrupts, high level
170 
171  if ( DOUBLESPEED == 1 )
172  {
173  pusart->CTRLB = USART_CLK2X_bm; // turn on 2x clock, 8 data bits, rcv and xmt disabled
174  }
175  else
176  {
177  pusart->CTRLB &= ~USART_CLK2X_bm; // turn off 2x clock
178  }
179 
180  pusart->CTRLC = USART_CHSIZE0_bm + USART_CHSIZE1_bm; // set for 8-bit, 1 stop, no parity
181 
182  pusart->BAUDCTRLB = baudb; // do this reg first!
183  pusart->BAUDCTRLA = bauda; // set up the baud rate
184 
185  pusart->CTRLB |= (USART_RXEN_bm | USART_TXEN_bm); // enable rcv and xmt
186 }
187 
188 /*
189  * USART_Connect() assign an USART to one of the standard I/O streams
190  */
191 void USART_Connect ( int usartnum, int streamsel )
192 {
193 
194  if ( usartnum >= NUM_USARTS ) return; // illegal USART selector, ignore
195 
196  if ( streamsel == IN_FILENO )
197  usartsel_in = usartnum;
198  else if ( streamsel == OUT_FILENO )
199  usartsel_out = usartnum;
200  else if ( streamsel == ERR_FILENO )
201  usartsel_err = usartnum;
202  else
203  return;
204 }
205 
206 
207 /*
208  * USART_putchar() write char c to selected stream
209  *
210  * If stream is not stdout or stderr, call is ignored.
211  */
212 static int USART_putchar ( char c, FILE *stream )
213 {
214  USART_t *ptr;
215 
216  if ( stream == &usartout )
217  ptr = usart[usartsel_out]; // point to active stdout USART
218  else
219  return 0; // is this right?
220 
221  while ( (ptr->STATUS & USART_DREIF_bm) == 0 )
222  ; // spin until ready to send
223  ptr->DATA = c; // send the char to selected USART
224  return 0;
225 }
226 
227 /*
228  * USART_getchar() read a char from the selected stream
229  *
230  * If the stream is not stdin, call is ignored.
231  */
232 static int USART_getchar ( FILE *stream )
233 {
234  int n;
235  int c;
236 
237  if ( stream != &usartin ) return 0; // is this right?
238 
239  n = usartsel_in; // shorthand
240  while ( inptr[n] == outptr[n] )
241  ; // spin until char is available...
242  c = queue[n][outptr[n]]; // pull char
243  outptr[n]++; // move to next cell
244  outptr[n] = outptr[n] & (QUEUE_SIZE - 1); // keep it legal
245  if ( c == '\r' ) c = '\n'; // convert CRs to LFx
246  return c;
247 }
248 
249 /*
250  * _rxcisr() low-level USART receive-char interrupt processor
251  *
252  * This routine is ONLY to be called by one of the recieve-char ISRs
253  * below!
254  *
255  * This routine updates the receive queue for the selected USART, based
256  * on the USART selecter passed as argument usartnum.
257  *
258  * If a queue overflows, the oldest char is lost.
259  */
260 static void _rxcisr ( int usartnum )
261 {
262  USART_t *pusart;
263 
264  pusart = usart[usartnum]; // point to correct USART
265  queue[usartnum][inptr[usartnum]] = pusart->DATA; // grab the data
266  inptr[usartnum]++; // move to next queue slot
267  inptr[usartnum] = inptr[usartnum] & (QUEUE_SIZE - 1); // keep it legal
268  if ( inptr[usartnum] == outptr[usartnum] ) // if caught up with outptr...
269  {
270  outptr[usartnum]++; // guess we lose the oldest char!
271  outptr[usartnum] = outptr[usartnum] & (QUEUE_SIZE - 1);
272  }
273 }
274 
275 /*
276  * These are the eight ISRs used to support receive-char interrupts for
277  * each USART.
278  *
279  * In every case, the ISR invokes _rxcisr() above with the enum associated
280  * with that ISR's USART.
281  */
282 
283 ISR(USARTC0_RXC_vect)
284 {
285  _rxcisr ( eUSARTC0 );
286 }
287 
288 ISR(USARTC1_RXC_vect)
289 {
290  _rxcisr ( eUSARTC1 );
291 }
292 
293 ISR(USARTD0_RXC_vect)
294 {
295  _rxcisr ( eUSARTD0 );
296 }
297 
298 ISR(USARTD1_RXC_vect)
299 {
300  _rxcisr ( eUSARTD1 );
301 }
302 
303 ISR(USARTE0_RXC_vect)
304 {
305  _rxcisr ( eUSARTE0 );
306 }
307 
308 ISR(USARTF0_RXC_vect)
309 {
310  _rxcisr ( eUSARTF0 );
311 }
312 
313 #ifndef BAUD_SETTINGS
314 #define F_CPU 32000000UL
315 
316 #define BAUDRATE 57600
317 #define F_PER F_CPU
318 #define BSEL_USART ((F_PER/(8*BAUDRATE))-1) /* 2x clock */
319 #define BAUD_A ((BSEL_USART) & 0xff)
320 #define BAUD_B ((BSEL_USART >> 8) | 0) /* BSCALE of 0 */
321 #endif
322 
Standardheader und Auswahl der Übertragungsgeschwindigkeit.