-
Notifications
You must be signed in to change notification settings - Fork 1
/
uart_test.cpp
201 lines (164 loc) · 5.39 KB
/
uart_test.cpp
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
#if 0
#include "Osc.hpp"
#include "Uart.hpp"
//xc32 v2.10, optimizations -Os , each function in section, remove unused sections
//data used = 72 bytes
//flash used = 4810 bytes
int main()
{
//set osc to 24MHz
Osc osc;
osc.pll_set ( osc.MUL12, osc.DIV4 );
//tx only
Uart info { Uart::UART2TX, Pins::C6, 230400 };
//8N1 (is default, so really no need to set)
info.mode ( info.MODE8N1 );
info.on ( true );
for(;;){
info.puts ( "Hello World? " );
}
}
#endif
#if 0
//here is a C version, doing minimal to get equivalent function as C++ code above
//xc32 v2.10, optimizations -Os , each function in section, remove unused sections
//data used = 0 bytes
//flash used = 2390 bytes
//also note that in the C++ version, there is more functionality brought in-
//osc will keep track of cpu speed
//baud will be calculated automatically (based on actual clock speeds)
//syskey unlock/lock is more robust (irq/dma accounted for)
//pin setup is done automatically- in/out/pullup/pps/etc
#include <xc.h>
void main(void) {
//osc to 24mhz, FRC as source
SYSKEY = 0xAA996655; //syskey unlock
SYSKEY = 0x556699AA;
OSCCONbits.NOSC = 0; //switch to frc before changing pll
OSCCONbits.OSWEN = 1; //enable switch
while(OSCCONbits.OSWEN); //wait till done
SPLLCONbits.PLLMULT = 5; //x12
SPLLCONbits.PLLODIV = 2; // /4
SPLLCONbits.PLLICLK = 1; //spll src=frc
OSCCONbits.NOSC = 1; //switch to spll
OSCCONbits.OSWEN = 1; //enable switch
while(OSCCONbits.OSWEN); //wait till done
SYSKEY = 0; //syskey lock
//uart2 tx->pin C6 (RP23), 230400 baud, 8N1
//C6 happens to not have analog function (no ansel), so no need to setup as pps overrides tris
RPOR5bits.RP23R = 4; //RP23 -> U2TX
U2MODEbits.BRGH = 1; //hispeed
U2BRGbits.BRG = 26; //230400 w/24MHz 24MHz/4/230400=26.04
U2MODEbits.PDSEL = 0; //8N
U2MODEbits.STSEL = 0; //1
U2STAbits.UTXEN = 1; //tx on
U2MODEbits.ON = 1; //uart on
const char hw[] = "Hello World? ";
for( ; ; ){
const char* p = hw;
for(; *p; p++){
while(U2STAbits.UTXBF); //wait if buffer full
U2TXREG = *p; //send
}
}
}
#endif
#if 1
//another uart test with irq
#include "Osc.hpp"
#include "Pins.hpp"
#include "Uart.hpp"
#include "Irq.hpp"
#include "Delay.hpp"
#include "Cp0.hpp"
//led status of uart- errors or activity with persist time
struct LedStatus {
enum LEDSTATE { OK, OERR, BITERR, NOCHANGE };
private:
using led_t = struct {
Pins pin;
Delay persist;
uint16_t ontime;
};
//rgb led on curiosity board
led_t leds[3] = {
{ {Pins::D1, Pins::OUT}, {}, 4000 }, //Red
{ {Pins::C3, Pins::OUT}, {}, 100 }, //Green
{ {Pins::C15, Pins::OUT}, {}, 4000 } //Blue
};
enum RGB { R, G, B };
//led's state
LEDSTATE state{NOCHANGE};
public:
//regular check/update from cp0 isr
void update(){
//check if persist time expired
for( auto& n : leds ){
if( n.persist.expired() ) n.pin.off();
}
//if no change to state, done
if( state == NOCHANGE ) return;
//change made, turn off all led's first
for( auto& n : leds ) n.pin.off();
//assume state is OK
RGB n = G;
if( state == OERR ) n = R;
else if( state == BITERR ) n = B;
//set delay and turn on
leds[n].persist.set( leds[n].ontime *1_ms);
leds[n].pin.on();
state = NOCHANGE;
}
//set led status (from rx isr)
void status(LEDSTATE s){ state = s; }
};
LedStatus leds;
//uart2 to Onion Omega2 uart1, 921600 baud (1Mbaud actual)
Uart info { Uart::UART2, Pins::C6, Pins::C7, 921600 };
int main()
{
Osc osc;
osc.pll_set( osc.MUL12, osc.DIV4 ); //24MHz
Irq::isr_func( Irq::UART2_RX,
[]{
//get errors before reading rx buf (for our own information)
uint8_t err = info.rx_err();
//get char-returns eof if any error,or if no data avaiable-
//(which should not happen in rx irq, that's why we are here)
//getc clears any errors by simply clearing the fifo buffer
int c = info.getc();
if( c >= 0 ){ //no error
leds.status(leds.OK);
info.putc( c ); //echo rx to tx
if( c == '\r' ) info.putc( '\n' ); //add nl to cr
//Delay::wait( 2_sec ); //to force overrun error
return;
}
if( err bitand 2 ) leds.status(leds.OERR);
else leds.status(leds.BITERR);
}
);
Irq::init( Irq::UART2_RX, 1, 0, true ); //pri=1, spri=0, on=true
info.on( true ); //turn on uart after osc (baud is set when turned on)
Cp0::compare_ms( 10 ); //cp0 irq every 10ms
Irq::isr_func( Irq::CORE_TIMER,
[]{
Cp0::compare_reload();
leds.update();
}
);
Irq::init( Irq::CORE_TIMER, 1, 0, true );
Irq::global( true );
//simple markup for ansi-
// @+ = turn on markup
// @! = reset colors/attributes
// @W = white, @R = red, @G = gren, @B = blue (capitol letters = foreground)
// @w = white, @k = black (lowercase letters = background)
//the uart inherits the Sprintf class, which does the printf work,
//along with the markup decoding
info.printf( "@+@!\r\n@WStarting uart echo test with @RL@GE@BD@W status...\r\n\r\n" );
for(;;){
Osc::idle(); //cp0 or rx2 will wake
}
}
#endif