-
Notifications
You must be signed in to change notification settings - Fork 6
/
serial.c
808 lines (638 loc) · 23.9 KB
/
serial.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
/* ************************************************************************
*
* TTL serial interface (hardware USART)
*
* (c) 2019-2022 by Markus Reschke
*
* ************************************************************************ */
/*
* hints:
* - port and pins for bit-bang serial (software USART)
* SERIAL_PORT port data register
* SERIAL_DDR port data direction register
* SERIAL_PIN port input pins register
* SERIAL_TX pin for Tx (transmit)
* SERIAL_RX pin for Rx (receive)
* - For hardware USART the MCU specific pins are used:
* ATmega 328:
* - USART0: RxD PD0 and TxD PD1
* ATmega 324/644/1284:
* - USART0: RxD PD0 and TxD PD1
* - USART1: RxD PD2 and TxD PD3
* ATmega 640/1280/2560:
* - USART0: RxD PE0 and TxD PE1
* - USART1: RxD PD2 and TxD PD3
* - USART2: RxD PH0 and TxD PH1
* - USART3: RxD PJ0 and TxD PJ1
*/
/* local includes */
#include "config.h" /* global configuration */
#ifdef HW_SERIAL
/*
* local constants
*/
/* source management */
#define SERIAL_C
/*
* include header files
*/
/* local includes */
#include "common.h" /* common header file */
#include "variables.h" /* global variables */
#include "functions.h" /* external functions */
/*
* local constants
*/
/* registers, bits and stuff for hardware USART */
/* USART0 */
#if SERIAL_USART == 0
#define REG_UDR UDR0 /* USART I/O Data Register 0 */
#define REG_UCSR_A UCSR0A /* USART Control and Status Register A */
#define BIT_RXC RXC0 /* USART Receive Complete */
#define BIT_TXC TXC0 /* USART Transmit Complete */
#define BIT_UDRE UDRE0 /* USART Data Register Empty */
#define BIT_FE FE0 /* Frame Error */
#define BIT_DOR DOR0 /* Data OverRun */
#define BIT_UPE UPE0 /* USART Parity Error */
#define REG_UCSR_B UCSR0B /* USART Control and Status Register B */
#define BIT_RXCIE RXCIE0 /* RX Complete Interrupt Enable */
#define BIT_RXEN RXEN0 /* Receiver Enable */
#define BIT_TXEN TXEN0 /* Transmitter Enable */
#define BIT_UCSZ_2 UCSZ02 /* USART Character Size 2 */
#define REG_UCSR_C UCSR0C /* USART Control and Status Register C */
#define BIT_UMSEL_0 UMSEL00 /* USART Mode Select 0 */
#define BIT_UMSEL_1 UMSEL01 /* USART Mode Select 1 */
#define BIT_UPM_0 UPM00 /* USART Parity Mode 0 */
#define BIT_UPM_1 UPM01 /* USART Parity Mode 1 */
#define BIT_USBS USBS0 /* USART Stop Bit Select */
#define BIT_UCSZ_0 UCSZ00 /* USART Character Size 0 */
#define BIT_UCSZ_1 UCSZ01 /* USART Character Size 1 */
#define REG_UBRR_L UBRR0L /* USART Baud Rate Register Low */
#define REG_UBRR_H UBRR0H /* USART Baud Rate Register High */
#define REG_UBRR UBRR0 /* USART Baud Rate Register combined */
#define ISR_USART_RX USART0_RX_vect /* ISR */
#endif
/* USART1 */
#if SERIAL_USART == 1
#define REG_UDR UDR1 /* USART I/O Data Register 1 */
#define REG_UCSR_A UCSR1A /* USART Control and Status Register A */
#define BIT_RXC RXC1 /* USART Receive Complete */
#define BIT_TXC TXC1 /* USART Transmit Complete */
#define BIT_UDRE UDRE1 /* USART Data Register Empty */
#define BIT_FE FE1 /* Frame Error */
#define BIT_DOR DOR1 /* Data OverRun */
#define BIT_UPE UPE1 /* USART Parity Error */
#define REG_UCSR_B UCSR1B /* USART Control and Status Register B */
#define BIT_RXCIE RXCIE1 /* RX Complete Interrupt Enable */
#define BIT_RXEN RXEN1 /* Receiver Enable */
#define BIT_TXEN TXEN1 /* Transmitter Enable */
#define BIT_UCSZ_2 UCSZ12 /* Character Size 0 */
#define REG_UCSR_C UCSR1C /* USART Control and Status Register C */
#define BIT_UMSEL_0 UMSEL10 /* USART Mode Select 0 */
#define BIT_UMSEL_1 UMSEL11 /* USART Mode Select 1 */
#define BIT_UPM_0 UPM10 /* USART Parity Mode 0 */
#define BIT_UPM_1 UPM11 /* USART Parity Mode 1 */
#define BIT_USBS USBS1 /* USART Stop Bit Select */
#define BIT_UCSZ_0 UCSZ10 /* USART Character Size 0 */
#define BIT_UCSZ_1 UCSZ11 /* USART Character Size 1 */
#define REG_UBRR_L UBRR1L /* USART Baud Rate Register Low */
#define REG_UBRR_H UBRR1H /* USART Baud Rate Register High */
#define REG_UBRR UBRR1 /* USART Baud Rate Register combined */
#define ISR_USART_RX USART1_RX_vect /* ISR */
#endif
/* USART2 */
#if SERIAL_USART == 2
#define REG_UDR UDR2 /* USART I/O Data Register 2 */
#define REG_UCSR_A UCSR2A /* USART Control and Status Register A */
#define BIT_RXC RXC2 /* USART Receive Complete */
#define BIT_TXC TXC2 /* USART Transmit Complete */
#define BIT_UDRE UDRE2 /* USART Data Register Empty */
#define BIT_FE FE2 /* Frame Error */
#define BIT_DOR DOR2 /* Data OverRun */
#define BIT_UPE UPE2 /* USART Parity Error */
#define REG_UCSR_B UCSR2B /* USART Control and Status Register B */
#define BIT_RXCIE RXCIE2 /* RX Complete Interrupt Enable */
#define BIT_RXEN RXEN2 /* Receiver Enable */
#define BIT_TXEN TXEN2 /* Transmitter Enable */
#define BIT_UCSZ_2 UCSZ22 /* Character Size 0 */
#define REG_UCSR_C UCSR2C /* USART Control and Status Register C */
#define BIT_UMSEL_0 UMSEL20 /* USART Mode Select 0 */
#define BIT_UMSEL_1 UMSEL21 /* USART Mode Select 1 */
#define BIT_UPM_0 UPM20 /* USART Parity Mode 0 */
#define BIT_UPM_1 UPM21 /* USART Parity Mode 1 */
#define BIT_USBS USBS2 /* USART Stop Bit Select */
#define BIT_UCSZ_0 UCSZ20 /* USART Character Size 0 */
#define BIT_UCSZ_1 UCSZ21 /* USART Character Size 1 */
#define REG_UBRR_L UBRR2L /* USART Baud Rate Register Low */
#define REG_UBRR_H UBRR2H /* USART Baud Rate Register High */
#define REG_UBRR UBRR2 /* USART Baud Rate Register combined */
#define ISR_USART_RX USART2_RX_vect /* ISR */
#endif
/* USART3 */
#if SERIAL_USART == 3
#define REG_UDR UDR3 /* USART I/O Data Register 3 */
#define REG_UCSR_A UCSR3A /* USART Control and Status Register A */
#define BIT_RXC RXC3 /* USART Receive Complete */
#define BIT_TXC TXC3 /* USART Transmit Complete */
#define BIT_UDRE UDRE3 /* USART Data Register Empty */
#define BIT_FE FE3 /* Frame Error */
#define BIT_DOR DOR3 /* Data OverRun */
#define BIT_UPE UPE3 /* USART Parity Error */
#define REG_UCSR_B UCSR3B /* USART Control and Status Register B */
#define BIT_RXCIE RXCIE3 /* RX Complete Interrupt Enable */
#define BIT_RXEN RXEN3 /* Receiver Enable */
#define BIT_TXEN TXEN3 /* Transmitter Enable */
#define BIT_UCSZ_2 UCSZ32 /* Character Size 0 */
#define REG_UCSR_C UCSR3C /* USART Control and Status Register C */
#define BIT_UMSEL_0 UMSEL30 /* USART Mode Select 0 */
#define BIT_UMSEL_1 UMSEL31 /* USART Mode Select 1 */
#define BIT_UPM_0 UPM30 /* USART Parity Mode 0 */
#define BIT_UPM_1 UPM31 /* USART Parity Mode 1 */
#define BIT_USBS USBS3 /* USART Stop Bit Select */
#define BIT_UCSZ_0 UCSZ30 /* USART Character Size 0 */
#define BIT_UCSZ_1 UCSZ31 /* USART Character Size 1 */
#define REG_UBRR_L UBRR3L /* USART Baud Rate Register Low */
#define REG_UBRR_H UBRR3H /* USART Baud Rate Register High */
#define REG_UBRR UBRR3 /* USART Baud Rate Register combined */
#define ISR_USART_RX USART3_RX_vect /* ISR */
#endif
/* registers, bits and stuff for bit-bang USART */
/* PCINT0-7 */
#if (SERIAL_PCINT >= 0) && (SERIAL_PCINT <= 7)
#define BIT_PC_IRQ PCIE0 /* Pin Change Interrupt Enable 0 */
#define BIT_PC_FLAG PCIF0 /* Pin Change Interrupt Flag 0 */
#define REG_PC_MASK PCMSK0 /* Pin Change Mask Register 0 */
#define ISR_PINCHANGE PCINT0_vect /* ISR */
#endif
/* PCINT8-15 */
#if (SERIAL_PCINT >= 8) && (SERIAL_PCINT <= 15)
#define BIT_PC_IRQ PCIE1 /* Pin Change Interrupt Enable 1 */
#define BIT_PC_FLAG PCIF1 /* Pin Change Interrupt Flag 1 */
#define REG_PC_MASK PCMSK1 /* Pin Change Mask Register 1 */
#define ISR_PINCHANGE PCINT1_vect /* ISR */
#endif
/* PCINT16-23 */
#if (SERIAL_PCINT >= 16) && (SERIAL_PCINT <= 23)
#define BIT_PC_IRQ PCIE2 /* Pin Change Interrupt Enable 2 */
#define BIT_PC_FLAG PCIF2 /* Pin Change Interrupt Flag 2 */
#define REG_PC_MASK PCMSK2 /* Pin Change Mask Register 2 */
#define ISR_PINCHANGE PCINT2_vect /* ISR */
#endif
/* PCINT24-31 */
#if (SERIAL_PCINT >= 24) && (SERIAL_PCINT <= 31)
#define BIT_PC_IRQ PCIE3 /* Pin Change Interrupt Enable 3 */
#define BIT_PC_FLAG PCIF3 /* Pin Change Interrupt Flag 3 */
#define REG_PC_MASK PCMSK3 /* Pin Change Mask Register 3 */
#define ISR_PINCHANGE PCINT3_vect /* ISR */
#endif
/* ************************************************************************
* functions for software USART (bit-banging)
* ************************************************************************ */
#ifdef SERIAL_BITBANG
/*
* set up serial interface
* - TX & RX line
*/
void Serial_Setup(void)
{
SERIAL_DDR |= (1 << SERIAL_TX); /* set TX pin to output mode */
SERIAL_PORT |= (1 << SERIAL_TX); /* preset TX to idle state (high) */
#ifdef SERIAL_RW
SERIAL_DDR &= ~(1 << SERIAL_RX); /* set RX pin to input mode */
REG_PC_MASK |= (1 << SERIAL_RX); /* set up pin change mask for RX pin */
/* hint: use Serial_Ctrl() to enable pin change interrupt later on */
#ifdef SAVE_POWER
/* we have to keep clk_IO running when sleeping */
Cfg.SleepMode = SLEEP_MODE_IDLE; /* default sleep mode: power idle */
#endif
#endif
}
/*
* send byte
* - 9600 8N1
*
* requires:
* - Byte: byte to send
*/
void Serial_WriteByte(uint8_t Byte)
{
uint8_t n = 8; /* bit counter */
/* R_PORT & R_DDR / ADC_PORT & ADC_DDR can interfere (input/HiZ) */
/* idea: add external pull-up resistor to TX to keep TX high while set to HiZ */
Serial_Setup(); /* quick and dirty */
/* start bit (0/low) */
SERIAL_PORT &= ~(1 << SERIAL_TX); /* clear TX */
wait100us(); /* delay for 9600bps */
wait3us();
/* 8 data bits (LSB first) */
while (n > 0)
{
if (Byte & 0b00000001) /* 1 */
{
SERIAL_PORT |= (1 << SERIAL_TX); /* set TX */
}
else /* 0 */
{
SERIAL_PORT &= ~(1 << SERIAL_TX); /* clear TX */
}
wait100us(); /* delay for 9600bps */
wait3us();
Byte >>= 1; /* shift right */
n--; /* next bit */
}
/* 1 stop bit (1/high) and stay idle (high) */
SERIAL_PORT |= (1 << SERIAL_TX); /* set TX */
wait100us(); /* delay for 9600bps */
wait3us();
}
#ifdef SERIAL_RW
/*
* control serial interface
*
* requires:
* - Control: control flag/switch
* SER_RX_PAUSE - pause RX (disable interrupt)
* SER_RX_RESUME - resume RX (enable interrupt)
*/
void Serial_Ctrl(uint8_t Control)
{
switch (Control)
{
case SER_RX_PAUSE: /* pause RX */
/* todo: send XOFF? */
PCICR &= ~(1 << BIT_PC_IRQ); /* disable pin change interrupt */
break;
case SER_RX_RESUME: /* resume RX */
PCIFR |= (1 << BIT_PC_FLAG); /* clear interrupt flag */
PCICR |= (1 << BIT_PC_IRQ); /* enable pin change interrupt */
/* todo: send XON? */
break;
}
}
/*
* ISR for PCIn (Pin Change Interrupt n)
* - 9600 8N1
* - for detecting start bit of RX
* - starts bit sampling by setting up timer
* - can't be used when by some measurement/tool needs Timer0
*/
ISR(ISR_PINCHANGE, ISR_BLOCK)
{
/*
* hints:
* - the PCIFn flag is cleared automatically
* - interrupt processing is disabled while this ISR runs
* (no nested interrupts)
*/
/* check if RX pin has changed to 0/low (start bit) */
if (! (SERIAL_PIN & (1 << SERIAL_RX))) /* low state */
{
PCICR &= ~(1 << BIT_PC_IRQ); /* disable pin change interrupt */
/* reset variables for new char */
RX_Char = 0;
RX_Bits = 0;
/*
* set up Timer0 for sampling first bit (start)
* - normal mode
* - use OCR0B for triggering interrupt
* - 1/2 bit period of 9600bps = 52.08µs
* - fixed prescaler = 8
* MCU clock [MHz]: 8 16 20
* timer cycle [µs]: 1 0.5 0.4
* cycles for 52µs: 52 104 130
* - we don't need high precision, just good enough to sample 10 bits
* - MCU_CYCLE_TIME in 0.1ns
* timer cycles = (52µs * 10000) / (MCU_CYCLE_TIME * 8)
* - use delay of 48µs for early sampling and to allow some time jittering
*/
#define HALF_BIT 480000 / (MCU_CYCLE_TIME * 8)
//TCCR0B = 0; /* stop timer */
TCNT0 = 0; /* reset counter to 0 */
OCR0B = HALF_BIT; /* set match value for 1/2 bit period */
TCCR0A = 0; /* normal mode (count up) */
TIFR0 = (1 << OCF0B); /* clear Output Compare B Match flag */
TIMSK0 = (1 << OCIE0B); /* enable Output Compare B Match interrupt */
TCCR0B = (1 << CS01); /* start timer by setting prescaler */
#undef HALF_BIT
}
/* else: ignore pin change to 1/high */
}
/*
* ISR for match of Timer0's OCR0B (Output Compare Register B)
* - 9600 8N1
* - sample RX bits
* - can't be used when by some measurement/tool needs Timer0
* - puts received char into a buffer
* - collects full text line and manages the buffer
*/
ISR(TIMER0_COMPB_vect, ISR_BLOCK)
{
uint8_t Bit; /* bit flag */
/*
* hints:
* - the OCF0B interrupt flag is cleared automatically
* - interrupt processing is disabled while this ISR runs
* (no nested interrupts)
*/
TCCR0B = 0; /* stop Timer0 */
/*
* sample RX bit
* - LSB first
*/
Bit = SERIAL_PIN & (1 << SERIAL_RX); /* get bit */
RX_Bits++; /* got another bit */
if (RX_Bits == 1) /* start bit */
{
/* start bit should be low */
if (Bit) /* high */
{
RX_Bits = 0; /* end RX */
}
}
else if (RX_Bits == 10) /* stop bit */
{
/* stop bit should be high */
if (Bit == 0) /* low */
{
RX_Bits = 0; /* end RX */
}
}
else /* data bit */
{
RX_Char >>= 1; /* shift right */
if (Bit) RX_Char |= 0b10000000; /* set MSB */
}
/*
* manage buffer
*/
if (RX_Bits == 10) /* got all bits */
{
if (! (Cfg.OP_Control & OP_RX_LOCKED)) /* buffer unlocked */
{
if (RX_Char == '\r') /* CR (carriage return) */
{
RX_Char = 0; /* terminate string */
}
else if (RX_Char == '\n') /* NL (new line) */
{
RX_Char = 0; /* terminate string */
if (RX_Pos > 0) /* not an empty line */
{
Cfg.OP_Control |= OP_RX_LOCKED; /* lock buffer for processing */
}
}
else if (RX_Pos == (RX_BUFFER_SIZE - 1)) /* no control char & overflow */
{
RX_Char = 0; /* terminate string */
/* lock buffer & signal overflow */
Cfg.OP_Control |= OP_RX_LOCKED | OP_RX_OVERFLOW;
}
RX_Buffer[RX_Pos] = RX_Char; /* copy to buffer */
if (RX_Char > 0) /* no control char */
{
RX_Pos++; /* next char */
}
}
/* else: drop char */
RX_Bits = 0; /* end RX */
}
/*
* rearm pin-change interrupt for next char
*/
if (RX_Bits == 0) /* char done, no more bits expected */
{
TIMSK0 = 0; /* disable Timer0 interrupts */
PCIFR |= (1 << BIT_PC_FLAG); /* clear pin change interrupt flag */
PCICR |= (1 << BIT_PC_IRQ); /* enable pin change interrupt */
}
else /* more bits expected */
{
/*
* set up Timer0 for sampling next bit (data or stop)
* - keep basic settings from RX pin change ISR
* - bit period of 9600bps = 104.1µs
* - fixed prescaler = 8 (<=16MHz) or 64 (>16MHz)
* MCU clock [MHz]: 8 16 20
* timer cycle [µs]: 1 0.5 3.2
* cycles for 104µs: 104 208 32.5
* - we don't need high precision, just good enough to sample 10 bits
* - MCU_CYCLE_TIME in 0.1ns
* timer cycles = (104µs * 10000) / (MCU_CYCLE_TIME * prescaler)
* - use a delay of 102µs to compensate for the runtime of this ISR
*/
#if CPU_FREQ <= 16000000 /* <= 16MHz */
/* prescaler 8 */
#define FULL_BIT 1020000 / (MCU_CYCLE_TIME * 8)
#define PRESCALER (1 << CS01)
#else /* > 16MHz */
/* prescaler 64 */
#define FULL_BIT 1020000 / (MCU_CYCLE_TIME * 64)
#define PRESCALER (1 << CS01) | (1 << CS00)
#endif
TCNT0 = 0; /* reset counter to 0 */
OCR0B = FULL_BIT; /* set match value for bit period */
TCCR0B = PRESCALER; /* start timer by setting prescaler */
#undef FULL_BIT
#undef PRESCALER
}
}
#endif
#endif
/* ************************************************************************
* functions for hardware USART
* ************************************************************************ */
#ifdef SERIAL_HARDWARE
/*
* set up serial interface
* - 9600 8N1
* - TX & RX line
*/
void Serial_Setup(void)
{
/*
* asynchronous normal mode
* - prescaler = (f_MCU / (16 * bps)) - 1
* - 2400bps, 8 data bits, no parity, 1 stop bit
* - overrides normal port operation of Tx pin and Rx pin (if enabled)
*/
REG_UBRR = (CPU_FREQ / (16UL * 9600)) - 1;
REG_UCSR_C = (1 << BIT_UCSZ_1) | (1 << BIT_UCSZ_0);
#ifdef SERIAL_RW
/* enable TX and RX */
REG_UCSR_B = (1 << BIT_RXEN) | (1 << BIT_TXEN);
/* hint: use Serial_Ctrl() to enable interrupt for RX Complete later on */
#else
/* enable TX */
REG_UCSR_B = (1 << BIT_TXEN);
#endif
#ifdef SAVE_POWER
/* we have to keep clk_IO running when sleeping */
Cfg.SleepMode = SLEEP_MODE_IDLE; /* default sleep mode: power idle */
#endif
}
/*
* send byte
* - 9600 8N1 (set by Serial_Setup())
*
* requires:
* - Byte: byte to send
*/
void Serial_WriteByte(uint8_t Byte)
{
/* wait for empty Tx buffer */
while (! (REG_UCSR_A & (1 << BIT_UDRE)));
/* clear USART Transmit Complete flag */
//REG_UCSR_A = (1 << BIT_TXC);
/* copy byte to Tx buffer, triggers sending */
REG_UDR = Byte;
}
#ifdef SERIAL_RW
/*
* control serial interface
*
* requires:
* - Control: control flag/switch
* SER_RX_PAUSE - pause RX (disable interrupt)
* SER_RX_RESUME - resume RX (enable interrupt)
*/
void Serial_Ctrl(uint8_t Control)
{
switch (Control)
{
case SER_RX_PAUSE: /* pause RX */
/* todo: send XOFF? */
REG_UCSR_B &= ~(1 << BIT_RXCIE); /* disable RXC interrupt */
break;
case SER_RX_RESUME: /* resume RX */
REG_UCSR_B |= (1 << BIT_RXCIE); /* enable RXC interrupt */
/* todo: send XON? */
break;
}
}
/*
* ISR for RXCn (Receive Complete n)
* - 9600 8N1 (set by Serial_Setup())
* - retrieves received character and puts it into a buffer
* - collects full text line and manages the buffer
*/
ISR(ISR_USART_RX, ISR_BLOCK)
{
unsigned char Char; /* character */
/*
* hints:
* - the RXCn flag is cleared by reading UDRn
* if not cleared it will retrigger the interrupt
* - interrupt processing is disabled while this ISR runs
* (no nested interrupts)
*/
/* todo: shall we allow nested interrupts for more critical things? */
/* todo: check receiver error flags? UCSRnA must be read before UDRn! */
Char = REG_UDR; /* get received char & clear flag */
if (! (Cfg.OP_Control & OP_RX_LOCKED)) /* buffer unlocked */
{
if (Char == '\r') /* CR (carriage return) */
{
Char = 0; /* terminate string */
}
else if (Char == '\n') /* NL (new line) */
{
Char = 0; /* terminate string */
if (RX_Pos > 0) /* not an empty line */
{
Cfg.OP_Control |= OP_RX_LOCKED; /* lock buffer for processing */
}
}
else if (RX_Pos == (RX_BUFFER_SIZE - 1)) /* no control char & overflow */
{
Char = 0; /* terminate string */
/* lock buffer & signal overflow */
Cfg.OP_Control |= OP_RX_LOCKED | OP_RX_OVERFLOW;
}
RX_Buffer[RX_Pos] = Char; /* copy to buffer */
if (Char > 0) /* no control char */
{
RX_Pos++; /* next char */
}
}
/* else: drop char, otherwise it would block the firmware */
}
#endif
#endif
/* ************************************************************************
* high level functions for TX
* ************************************************************************ */
/*
* write one char
* - converts custom LCD characters to standard ones
*
* requires:
* - Char: character to output
*/
void Serial_Char(unsigned char Char)
{
switch (Char)
{
case LCD_CHAR_DIODE_AC: /* diode icon '>|' */
Serial_WriteByte('>');
Serial_WriteByte('|');
break;
case LCD_CHAR_DIODE_CA: /* diode icon '|<' */
Serial_WriteByte('|');
Serial_WriteByte('<');
break;
case LCD_CHAR_CAP: /* capacitor icon '||' */
Serial_WriteByte('|');
Serial_WriteByte('|');
break;
case LCD_CHAR_OMEGA: /* omega */
Serial_WriteByte('R');
break;
case LCD_CHAR_MICRO: /* µ / micro */
Serial_WriteByte('u');
break;
case LCD_CHAR_RESISTOR_L: /* resistor left icon '[' */
Serial_WriteByte('['); /* or maybe 'V'? */
break;
case LCD_CHAR_RESISTOR_R: /* resistor right icon ']' */
Serial_WriteByte(']'); /* or maybe 'V'? */
break;
#ifdef UI_PROBE_REVERSED
case LCD_CHAR_1_INV: /* 1 (reversed color) */
Serial_WriteByte('1');
break;
case LCD_CHAR_2_INV: /* 2 (reversed color) */
Serial_WriteByte('2');
break;
case LCD_CHAR_3_INV: /* 3 (reversed color) */
Serial_WriteByte('3');
break;
case LCD_CHAR_X_INV: /* x (reversed color) */
Serial_WriteByte('x');
break;
#endif
default: /* standard char */
Serial_WriteByte(Char);
}
}
#if defined (UI_SERIAL_COPY) || defined (UI_SERIAL_COMMANDS)
/*
* send carriage return and linefeed
*/
void Serial_NewLine(void)
{
Serial_WriteByte('\r'); /* send CR */
Serial_WriteByte('\n'); /* send LF */
}
#endif
/* ************************************************************************
* high level functions for RX
* ************************************************************************ */
/* ************************************************************************
* clean-up of local constants
* ************************************************************************ */
/* source management */
#undef SERIAL_C
#endif
/* ************************************************************************
* EOF
* ************************************************************************ */