Embedded_Systems_L6(UARTs&pps)

advertisement
EEE527
Embedded Systems
Lecture 6 UARTs and applying PPS
"Adapted from the text “Programming 32-bit Microcontrollers in C –
Exploring the PIC32 , © 2008.” Lucio di Jasio
Ian McCrum
Room 5B18, Tel: 90 366364 voice mail on 6th ring
Email: IJ.McCrum@Ulster.ac.uk Web site: http://www.eej.ulst.ac.uk
www.eej.ulster.ac.uk/~ian/modules/EEE527/files
Simplified UART block diagram
figure 19-1 (DS61143)
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Baud Rate setting
In our case this translates to the following expression:
U2BREG = (25,000,000 / 4 / 115,200) -1 = 53.25
To decide how to best round out the result, use the reverse formula to calculate the
actual baud-rate and determine the percentage error:
Error = ((Fpb / 4 / (U2BREG + 1)) – baud rate) / baud rate %
With a value of 53 -> 115,740 Baud with an error of just 0.47%,
With a value of 54 -> 113,636 baud, 1.82% error,
Both are within the acceptable tolerance range for a standard RS232 port (+/- 2%) .
We can therefore define the constant BRATE as:
#define BRATE
53
// 115,200 Bd (BREGH=1)
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Use Excel to Calculate values
See the File
EEE527_PIC32MX_BAUD_RATE_GENERATOR.xlsx
SYS_CLK
PB divisor
PBCLK
Baudrate
UxBRG
=PBCLK/(4*baud) -1'
Number
Number
Formula
e.g
C8=A8/B8
Number
Formula
e.g
E8=C8/(4*D8) - 1
50000000
50000000
50000000
50000000
50000000
2
2
2
2
2
25000000
25000000
25000000
25000000
25000000
115200
38400
19200
9600
1200
53.25347222
161.7604167
324.5208333
650.0416667
5207.333333
Actual Baudrate
Error
for Rounded down
Round up
=PBCLK/(4*(UxBRG+1))'
Formula
Formula
Formula
Formula
e.g
e.g
e.g
e.g
=roundown(E8,0)
G8=C8/((4*(F8+1))
(G8-D8)/D8 =roundup(E8,0)
Round Down
53
161
324
650
5207
115740.7407
38580.24691
19230.76923
9600.614439
1200.076805
0.47%
0.47%
0.16%
0.01%
0.01%
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
54
162
325
651
5208
Actual Baudrate
for Rounded up
Error
Formula
e.g
J8=C8/(4*(I8+1))
Formula
e.g
(G8-D8)/D8
113636.3636
38343.55828
19171.77914
9585.889571
1199.84642
-1.82%
-0.61%
-0.31%
-0.15%
-0.02%
UxMODE register
register 18-1 (DS61168E)
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Important BITs of UxMODE
ON (bit 15)
1 is enabled, UARTx pins controlled by UEN<1:0> and UTXEN
SIDL (bit 13)
only relevant in idle mode
IREN (bit 12)
0 = IrDA is disabled
RTSMD (bit 11) 1 = /UxRTS is in Simplex mode
UEN (bits 9-8)
00 = Use UxTX/RX, /UxCTS ,/UxRTS/BCLK just used by PORTx
WAKE (bit 7)
only relevant in sleep mode
LPBACK (bit 6) 0 = loopback disabled
ABAUD (bit 5 ) 0 = Auto-Baud rate detection is disabled or completed.
RXINV (bit 4)
0 = UxRX idle state is a ‘1’ ( sent in RS232 as -12V!)
BRGH (bit 3)
1 = High-speed mode – 4x baud clock enabled. {0= x16}
PDSEL (bits2-1) 00 = 8 bit data, no parity {01=8E, 10=8O (odd), 11=9N }
STSEL (bit 0)
0 = 1 stop bit {1 = 2 stop bits}
- - - - - - - - - - - - - - - - 1ux0 1u00 x000 1000 = 0x8888
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
UxSTA register
register 18-2 (DS61168E)
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Important BITs of UxSTA
ADM_EN
ADDR<7:0>
UTXISEL<1:0>
UTXINV
URXEN
UTXBRK
UTXEN
UTXBF
TRMT
URXISEL<1:0>
ADDEN
RIDLE
PERR
FERR
OERR
URXDA
(bit 24) 0 = no automatic address detect
(bits 23-16) only matter when bit above is set
(bits15-14) 01 = raise interrupt when all chars transmitted
(bit 13) 0 = UxTX idle state is ‘1’ (if not in IrDA mode)
(bit 12) 1 = UARTx receiver is enabled
(bit 11) 0 = send no break {1=send start, 12 ‘0’ and stop}
(bit 10) 1 = UARTx transmitter is enabled
(bit 9) 1 = Transmit buffer is full {0 = room for at least 1 char}
(bit 8) 0 = Transmit Shift Register is not empty, tx in progress
(bit 7-6) 00 = Int flag is asserted while rx buffer not empty
(bit 5) 0 = Address detect mode disabled
(bit 4) 0 = Data is being received {1=receiver is idle}
(bit 3) 1 = Parity error detected for current character
(bit 2) 1 = Framing error detected for current character
(bit 1) 1 = Receiver buffer overrun. Can only be cleared in s/w
(bit 0) 1 = Receive buffer data available, at least one char.
e.g. U2STA = 0x1400;
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Further restraints – the DP32 schematic
NB, link only
One of these
Pin 1
3V3 REG
DC IN
J6
MCLR
JP7
21
JP1
9
D-/RB11
D+/RB10
10
RB0/PGD
RB1/PGC
RB2
RB3
4
5
6
7
RB4
11
BTN2
RB7
16
BTN3
LED 3
LED 2
LED 1
LED 0
RA3/OSC2
(CS)RA0
25
RB13(AN11)
(SDI)RA1
I2C – or use PPS to set them to UART2
17
RB15(AN9)
(SD0)RA4
18
LEDs all via
4k7 to base
of transistors
‘1’ lights LED
10k series
Resistors and
10k pullups,
Switches to ground
10k Variable resistor 3v3 to 0v,
feed to slider via 1k
RA2/OSC1
(SCL1)RB8
2k2
3V3 0V
PGD PGC
RB5/USBID (for USB OTG)
(SDA1)RB9
2k2
USB – or use PPS to
set them to UART1
(SCK1)RB14
To 8MHz XTAL Via 680R
and With 30pF caps
JP5
JP6
PIC32MX250F128B
28 PIN DIL PACKAGE
VBUS
14
MCLR
JP2
AVSS
22
1
VSS
JP3
MINI –
USB
For
power &
bootloa
ding
AVDD
15
VDD
23
VUSB
20
VCAP
8 19 27
VSS
28
13
ICSP to PICKIT3
Programmer
12
3
2
26 VR1
24
SPI – or use PPS to set them to UART1
IC3
10k
using PPS you can wire U1RX to RA2,RA4,RB2 ,or RB13. U1TX to RA0,RB3,RB4,RB7 or RB15
U2RX to RA1,RB1,RB5,RB8,RB11 and U2TX to RA3,RB0,RB9,RB10 or RB14 (lose USB or I2C?)
Supplies temperature as
Voltage, MCP9701A
Sensor, 3 pin TO92
Diagram of DP32 board,
see full schematic for
details!
In the DP32 it is simpler to use UART2 – it shares pins with the
I2C pins going to JP4 & 5
Use UART2 and PPS ->
U2TX/RPB9
U2RX/RPB8
NB
Remove jumpers JP4 & 5
And do not insert IC2C, the 8 pin
chip
You need to program which pins go where – look up Peripheral Pin Select (PPS)
in the datasheet. Also the PPS LOCK and UNLOCK sequences.
Next 4 slides give working code; create a project called
UART_1 and either
wire RB8 and RB9 to a USB TTL 3.3V Usart,
or a PICKIT2
or to another DP32 - but wire
RB8_board1 to RB9_board2
And
RB9_board2 to RB8_board2
(on the PC run PUTTY or PICKIT2 v2.6.1
(NOT PICKIT3 s/w!)
Code to demo serial i/o
Modified from http://umassamherstm5.org/tech-tutorials/pic32-tutorials/pic32mx220-tutorials/uart-to-serial-terminal
NB remove JP4 and JP5 (rotate 180
degrees)
Modified from http://umassamherstm5.org/tech-tutorials/pic32-tutorials/pic32mx220-tutorials/uart-to-serial-terminal
Modified from http://umassamherstm5.org/tech-tutorials/pic32-tutorials/pic32mx220-tutorials/uart-to-serial-terminal
Modified from http://umassamherstm5.org/tech-tutorials/pic32-tutorials/pic32mx220-tutorials/uart-to-serial-terminal
Exercises
• Send data every second to another DP32 and
display it there. (The sending board can be called
DP32_1 and the receiver DP32_2)
• Send data only when a pushbutton on DP32_1 is
pressed.
• Send data only when the receiving end says it is
ready. (hint wire another wire from a spare i/o line
from Dp32_2 to DP32_1.
• Use LEDs to show various things
Timer delays
• These can use an interrupt – see notes for a 1 second ISR using a flag variable that
main polls.
• A simple delay is a “blocking” wait. E.g
#define DELAY 39062 // assuming 40Mhz clock
…
// In main near start
T1CON = 0x8030; // prescale 256:1, 40Mhz=25nSec and 25/256=> 6.4usec
Then for a delay use in your code the following two lines (or put in a function)
TMR1=0;PR1=0xFFFF; // Note the 39062 gives a slight inaccuracy.
while(TMR1 < DELAY){;}// wait here for 39062 * 6.4uSecs
// you arrive here after a quarter second…(reasonably accurate…)
You can also use the plib library (this code needs modified for the DP32! Do not use as is
PPSUnLock;
// Allow PIN Mapping
PPSOutput(4, RPB10, U2TX);
// MAP Tx to PB10
PPSInput (2, U2RX, RPB11);
// MAP Rx to PB11
PPSLock;
// Prevent Accidental Mapping
// Configure UART2
UARTConfigure(UART2, UART_ENABLE_PINS_TX_RX_ONLY);
UARTSetLineControl(UART2
,UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTSetDataRate(UART2, GetPeripheralClock(), BaudRate);
UARTEnable(UART2
,UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));
This code is explained at
http://www.eevblog.com/forum/microcontrollers/pic32mx-quickstart/15/
Print a message Function using plib
void Serial_print(char *buffer)
{
while(*buffer != (char)0)
{
while(!UARTTransmitterIsReady(UART2));
UARTSendDataByte(UART2, *buffer++);
}
while(!UARTTransmissionHasCompleted(UART2));
UARTSendDataByte(UART2, '\r');
UARTSendDataByte(UART2, '\n');
}
This code is explained at
http://www.eevblog.com/forum/microcontrollers/pic32mx-quickstart/15/
Sending and Receiving Data using
handshake lines – CTS and RTS (manually)
int putU2( int c)
{
while ( CTS);
while ( U2STAbits.UTXBF);
U2TXREG = c;
return c;
} // putU2
// wait for !CTS, clear to send
// wait while Tx buffer full
Could be worth adding the lines, just
before the return c;
while( !U2STAbits.TRMT);
char getU2( void)
{
RTS = 0;
// assert Request To Send !RTS
while ( !U2STAbits.URXDA); // wait for a new char to arrive
RTS = 1;
return U2RXREG;
// read char from receive buffer
}// getU2
Serial terminal programs on the PC
• Hyperterminal – pre windows 7 in all versions
• RealTerm - most excellent, doesn’t work W8
• Putty – usually used for network login but can use serial ports, use
this in block 6 lab PCs
• MPIDE has a good serial monitor
Use USB to serial convertors if the PC has no serial ports
• PICKit 2 can do USB to Serial conversion (but not yet working on the
PICKit 3) Select 3.3V before plugging in.
• You can buy USB to Serial convertors, either full RS232 or just TTL
UART. Be careful you do not damage the board! You want 3.3Volts
maximum Also several I have used output on pins labelled RCV and
input on TX – I had to use a scope to check!
HyperTerminal Setup (windows XP only)
RealTerm runs on XP and windows 7 (but not 8)
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Use the Device
manager to
check the COM
port of the USBTTL adaptor
PUTTY can perform serial terminal
functions
Ensure the
Speed is correct
When programming the PIC32 and with
the UART output connected to Putty
many random characters are sent from
the PIC to PUTTY.
If the handshaking is left at the default
XON/XOFF then PUTTY may receive a
XOFF (control-S) from the PIC and you
have to quit and restart PUTTY after
every programming
Alternatively select the correct
handshaking protocol. Such as clicking
on the Serial menu option and selecting
“NONE” or “HARDWARE RTS/CTS”
PICKit2 comes with UART Software – NB
NOT the PICKit3 yet, (Oct 2k14)
Wire up the PICKit2 as
PICKit Pin 1 - No Connection
PICKit Pin 2 - 3V3
PICKit Pin 3 - GND
PICKit Pin 4 – DP32 Pin 7 (Tx) RB14
PICKit Pin 5 - DP32 Pin 10 (Rx) RA1
PICKit Pin 6 - No Connection
Start the PICKit 2 application and
select Tools-->UART Tool
The
PICKit2
has
other
uses;
You can also use the Logic Analyzer Mode.
Click 'Exit UART Tool' and start the Logic Tool
Select 'Analyser' if it is not on by default.
Set the Sample rate to 100 Khz and the Trigger to Ch1 \ (falling edge)
Click Capture and, When your code sends 'Hello World!' you should see…
Tips and Tricks
To re-direct the output stream of the standard C library (stdio.h)
functions such as printf() to a UART:
•Define the function: _mon_putc()
– Note that a “weak” definition is already provided in the library to send
the default output stream (stdout) to UART2 (convenient for all
Explorer16 users).
•Similarly define: _mon_getc()
– A default “weak” version is already provided in the library as well,
connecting UART2 receiver to the input stream (stdin).
– Weak means that the compiler won’t complain when you define a new
function with the same name, it will simply replace it with the new one
you provide.
NOTE
•You are responsible for the UART initialization!
•Before the first call to any stdio function (printf()…) make sure the
UART2 is enabled and the baud rate is set correctly.
Code for serial i/o, allowing printf & puts
By adding a function called _mon_putc() the linker will use it for calls to printf() and puts()
Once you define _mon_putc() any call to printf or
puts will just work
I couldn’t get it working for _mon_getc() – I
expected gets to work… instead use code
below
Device Drivers
• It is good practice to partition big systems
into smaller sub-systems
• Each sub-system should do one function,
easy to describe (easy to test!)
• The interaction between these “modules”
should be minimised, clear and simple.
• For input-output devices this is
straightforward (usually)
• We can call these i/o modules “Device
Drivers” (these become VERY important
when we use embedded Operating Systems)
From : Di Jasio - Programming 32-bit Microcontrollers in C with additions by Ian McCrum
Using multiple files in C
• If working on a large project, you can split it into
several sections – you need only recompile one
part if you only change that part.
• The linker bundles together all the object files and
any library files that are needed.
• The “make” program can automate this
• IDEs use the concept of “projects” to bundle
related files together and ease building a complete
executable.
• In the project navigator, ensure your .c files are
listed under sources and your .h files under the
header file section.
What belongs in a header file?
• A good “google topic” as opinions vary, but only when very complex programs are
involved.
• http://www.embedded.com/electronics-blogs/barr-code/4215934/What-belongsin-a-header-file
• http://embeddedgurus.com/barr-code/2010/11/what-belongs-in-a-c-h-headerfile/
• http://programmers.stackexchange.com/questions/167723/what-should-andwhat-shouldnt-be-in-a-header-file
• http://stackoverflow.com/questions/1945846/c-what-should-go-into-an-h-file
• http://www0.egr.uh.edu/courses/ece4437/labsupport/Notes/What%20belongs%2
0in%20a%20header%20file.pdf where Michael Barr refers to his book on
“Embedded C Coding Standards”
.h files
• DO create one .h file for each module of a system apart from main.c. Include it first in the
.c file before the .c #includes anything else.
• DO use “guards” to avoid preprocessing a .h more than once
#ifndef headername_h
#define headername_h
… rest of .h goes here
#endif
• DO include all function prototypes required to use the module. You can “hide” private
functions by declaring them static.
• DO NOT add anything that creates code (usually)
• SOME say never have variables shared between modules – use functions to access
another module’s variables. Such data hiding and abstraction is good practice – see C++
for better examples.
• Declare global variables as extern in the .h, then declare and initialise them in the .c
extern uint8_t varx ; // extern means memory&content is allocated elsewhere
uint8_t varx=42; // inside the .c Hence memory gets allocated here
• Every header should include every other header needed to allow compilation of itself but
the .c should include whatever other headers that are needed. This is needed where a
stuct declaration needs to know information from another .h file. In general we will NOT
have to #include other .h files within our .h files
Our Embedded System
• Create ADC.h and ADC.c – initialiseADC() and readADC().
• Create UART.h and .c with initialiseUART(), and all other
UART functions.
• timer.h & .c initialiseTIMERS()
– SPI.h&.c (week 6)
• network.h&.c (we will create a UART or IIC system later)
• interrupts.h&.c to initialise interrupts and all ISRs (this is a
marginal design choice as you could put ISRs in main or
with each associated peripheral)
• You might (often) have a single setup.h&c to setup all
hardware. The method above eases porting code to a new
system
Exercises
• Write code that prints ADC values to serial port 2. Print
one value per line.
• Sample 100 values from the ADC into a buffer and then
output this to the PC when a button has been pushed.
• Configure UART1 using PPS and pins RB13 and RA0.
Print from one UART to another. (hint: make sure you
only output one character, then wait for it to be
received before outputting the next)
• Create UART, ADC and timer device libraries, (uart.c,
uart.h, adc.c, adc.h, timer.c and timer.h)
Download