Digital IO PDF

Title Digital IO
Author P. Ng
Course Micro-Controller Based Systems
Institution University of the West of England
Pages 10
File Size 450.9 KB
File Type PDF
Total Downloads 63
Total Views 156

Summary

Digital IO...


Description

3

Digital I/O

The aim of this week’s session is to explore digital I/Os of the dsPIC30F family. Again, our examples will be based on the dsPIC30F4011 and you will need to have the datasheet and the relevant section of the Family Reference available. This is all on blackboard. We will look at the ports from a hardware and software point of view.

3.1

Pins are shared

Almost all pins on your dsPIC device can act as digital inputs or outputs and you can set their state in software. However, many pins are shared between several peripherals and an I/O port that shares a pin with another peripheral is always subservient to the peripheral. For example, when PWM1 peripheral

Figure 21: Symbolic illustration of a dsPIC30F4011 in a 40 pin DIP. Note that many I/O pins can be driven by several peripherals. is enabled you cannot use pin 37 and 38 (RE1 and RE0) as digital I/O. If you want to use a pin as a digital I/O, make sure that the peripherals are disabled. Luckily, the default state (i.e. the state after reset) of the peripherals is normally off, but you should always check the data sheet if in doubt. A more detailed view of the shared port infrastructure is shown in figure 22. The output multiplexers allows the peripheral to direct its outputs to the pin when the peripheral is enabled. Otherwise, the port is controlled by the parallel I/O logic (PIO)on the bottom left.

3.2

The I/O port structure

Assuming that shared peripherals are disabled, you can control port in software by setting or clearing certain bits in the associated special function registers. In order to understand the effect of those bits, the block diagram of the port control structure is presented in figure 23. To control a port PIN, you can read and write three different bits. The tristate bit (TRIS) controls if a port works as an output or an input. The default state after reset is input. If you set TRIS to 1, the port is configured as an input; if you set TRIS to 0, the port is configured as an output3 . 3 This is quite easy to remember, the 1 looks a bit like an I for Input and the 0 looks a bit like an O for Output

17

Figure 22: Block-diagram view of the shared port structure.

Figure 23: Block diagram of an individual I/O port.

18

You can read the state of the port pin by simply reading the PORT bit. What you read will always be the logic state of the pin after the Schmitt trigger (see figure 23, ‘I/O Cell’). When you write to the PORT bit, the controller will actually set the latch (LAT) bit and the output latch then drives the port. You can also read from the LAT which will give you the logic state of the output latch. Note that the logic state of LAT and PORT can be different since the voltage on the pin is a function of the load (i.e. what you connect to the pin). The LAT, on the other hand, always has the logic state you have set it to.

3.2.1

I/O programming

From a software point of view, the operations described above are performed by reading and writing to the SFRs associated with the digital I/O pin. All I/O ports are organised in groups of 16 and are named alphabetically (A,B,C etc). In figure 24 the SFR’s associated with port D are shown. The registers are called TRISD, PORTD and LATD and they are mapped to certain memory locations. You can read or write the whole register or set bits individually. You

Figure 24: Internal view of the shared port structure. will also find the names of the registers shown in figure 24 in the header file associated with our device (e.g. p30F4011.h). In C, access to individual bits is implemented via bit-fields. Furthermore, the header file contains multiple #defines to simplify your code. For example, in order to set the tristate bit for bit 2 of port D, we can write: • TRISDbits.TRISD2=1; (prefered, because it does not hide information) • or, alternatively • _TRISD2=1; Additionally, you can use the bitwise AND and OR operators (&, | ) and a mask in C to set individual bits. The examples above represent a general mechanism. In order to program the peripherals of your microcontroller, first have a look at the data sheet to find out which bits you need to set. Then find the representation of those bits in the associated header file (they are mostly named exactly as they are referred to in the data sheet). Finally, you can use the C programming language to set and clear bits or whole registers in your code. 3.2.2

Good practice in embedded software engineering

It is generally good practice in software engineering to split up your project into functional modules. In C++ this is achieved with classes. In C we can aim 19

to achieve a similar level of organisation by putting variables, data structures (struct, enum etc) and functions that belong together into the same C-file. For a microcontroller, it is suggested that you put the code you write for each peripheral in a separte *.c and *.h file. This not only organises your project neatly but also helps you to recycle code in later projects4 . For your first experiments with digital I/Os, your project could be organised as shown in figure 25.

Figure 25: Example of MPLABX project with more than one c and header file. In gpIO.c you would implement all functions associated with digital I/O, for example void setupIOPorts(void). In the header gpIO.h you would declare this function so that other modules (C files) could be made aware of it via #include "gpIO.h" . The main.c could then look like this: #include //lets set the device configuration bits using the pre-processor macros _FOSC(PRI & XT_PLL8 & CSW_FSCM_OFF ); //primary oscillator with 8 times pll no clock s _FWDT(WDT_OFF); //watch dog is disabled _FBORPOR( PBOR_OFF & MCLR_EN & PWRT_64 & PWMxL_ACT_HI & PWMxH_ACT_LO &RST_PWMPIN); //brown out disabled, master-clear enabled, power on reset time = 64ms

#include "gpIO.h" //required to access and configure I/O void myWait(int time_ms); //forward declaration, use your function name here int main(void) { //initialise all necessary IO: gpIOSetup(); 4 There are alternative ways to organise your project and you are free to explore those. However, you should avoid putting all functions together in one file!

20

while(1) { LED2=~LED2; //toggles LED2 myWait(500); //waits 500ms } ... //somewhere down here you should have implemented your delay function //in this example this function is called void myWait(int time_ms). // This partial example sets up the I/O correctly by calling the gpIOSetup() function. After this, it enters an infinite loop and toggles LED2, waits for 500ms, toggles LED2 etc. Note that LED2 is a #define one would declare in the gpIO.h header. It is generally good practice to define all I/O ports with good, readable names. Also open the p30F4011.h in your projct. This is not strictly necessary but it is sometimes nice to look up the names of certain registers. Including this header into your project gives you an easy access to this information. You can either link to the file (it is stored with your compiler) or make a copy of it into your project folder and include it from there.

3.3

The ‘Analogue’ side of digital ports

Even though we use the port as a digital I/O, they are, as all things in nature, fundamentally analogue. This means they cannot be treated like a purely logical device. Rather, we need to have an understanding of their underlying hardware structure in order to avoid destroying the hardware. Some I/O Facts: • maximum current (sunk or sourced) by any I/O pin: 25mA • maximum combined current (sunk or sourced) by all ports: 200mA • maximum current of Vdd and Vss pins: 250mA • voltage on any pin with respect to Vss : −0.3V .. Vdd + 0.3V • maximum clamping current: 20mA It becomes clear that it very easy to overload your dsPIC, just 10 ‘normal’ 20mA LED are enough to reach the maximum current. Keep these limits in mind. Employ the appropriate drivers if necessary. Also consider that a large capacitive load can lead to very high instantaneous currents when the logic state changes. Every input into a CMOS device you can consider as a capacitive load since you need to charge the gate of the input transistor. Keep in mind the parasitic capacitors of most electronic devices (diodes, MOSFETS, resistors etc). 3.3.1

Clamping Diodes

Figure 26 below illustrates the clamping diodes that exist on the I/O ports.

21

Figure 26: Illustration of the clamping diodes of an I/O pin. Note that they can only tolerate a continuous current of 20mA and that they are there for ESD protection.

The transistors T1 and T2 drive the pin either high or low when the port is configured as an output. The amplifier Ain is the first stage of the input circuitry. The diodes D1 and D2 (Shottky diodes, Vf orwared ≈ 0.3V ) are the clamping diodes. A voltage slightly higher than Vdd or slightly lower than Vss will cause a current to flow through the diodes towards Vdd or Vss . As noted above, this current must not exceed 20mA. The clamping diodes are there for ESD protection, they are not free-wheeling diodes! If you need a free-wheeling diode, connect them externally. Also, be aware when connecting two digital circuits together that are supplied by two different power supplies. If these supplies come on with a slight delay, you can very, very quickly destroy the output’s driving transistors or the clamping diodes and consequently your microcontroller. This is illustrated in figure 27. Since you are very likely to design a system with more than one microcontroller and possibly more than one power supply, you should carefully consider this issue. 3.3.2

Floating inputs and bouncing switches

It is also important to consider that an input to dsPIC has a very high impedance and can be considered as mainly capacitive. This means that any input that is not connected to a high or low signal (e.g. 5V or Gnd respectively) is ‘floating’. Floating means that the logic level of an input in undefined and it can erratically change between high and low. The solution to this problem is a pull-up or pulldown resistor as shown in figure 28. For some pins on the dsPIC, weak internal pull-ups are provided (CN0..CN7, see data sheet). With mechanical switches and buttons there can be further complications. Due to their mechanical design some of those switches ‘bounce’. Bouncing means that when the (internal) switch is manually flicked, the internal contacts meet and mechanically bounce back and forth. This mechanical oscillation settles after a short time. Figure 29 shows the waveform of the signal on a digital input on a microcontroller connected to a switch and a pull-down resistor. With the time resolution of 1ms/div it appears as if a ‘clean’ rising edge is created and the signal changes from logical low to high. However, a zoomed view

22

Figure 27: Two integrated circuits with two different supplies Vdd 1 and Vdd 2 and a common ground connection. If IC1 is supplied earlier than IC2 and IC1 has an output driving an input of IC2, the clamping diodes will become forward conductive and IC2 is supplied through D2 of IC1. This ‘back-door’ supply will exceed the current limit of the clamping diode as well as the current limit of T2 of IC1 and the consequence can be catastrophic. The red red lines illustrate the current flow.)

Figure 28: To avoid floating inputs use pull-down (pin 2,11) and pull-up (pin 3) resistors if inputs are connected to switches.

23

Figure 29: The flicking of a switch appears to produce a clean rising edge, at least when observed with a resolution of 1ms/div.

of the same signal shown in figure 30 reveals the true nature of this transition. The switch bounces and creates a train of signal transitions. This would cause

Figure 30: The time resolution of 20µs/div reveals the bounce of the switch. problems if the signal is used directly, for example as an input into a counter or as a signal to toggle an electric motor.5 There are mechanical, electronic and software means to de-bounce switches. Some buttons and switches do not bounce. You could use capacitors and resistors to low-pass filter the signal. You could use software to sample the pin and only recognise the signal as high or low when it has been stable for a certain amount of time, e.g. 1ms. 5 Toggling is the pressing of a button which switches the motor on and the next pressing of the same button which switches the motor off. A further pressing of this button switches the motor on (and so forth).

24

3.4

Exercises: Programming I/O ports

The exercises below should be carried out on dsPIC1 on the Firecracker board. The Firecracker is not a fool-proof toy but a prototyping platform for the professional user. Make sure you understand the circuit before you use it. Set the supply voltage to 7V or use a USB cable to power your board. In order to program your device connect your ICD2/PICkit3 to the Firecracker board. Select ICD2/PICkit3 as programmer (Dashboard->Project Properties if you have not choosen the programmer during project setup.). Connect to the target to establish communication. You may want to run the programmer/debugger selft test (Debug->Run Programmer/Debugger self test). Write your code, build your project and and program the target. Document all those exercises in your log-book. You may want to create separate files or even folders for the separate exercises. Keep those files for evaluation of your work. 1. Write down, based on the circuit diagram, which pins/registers are used as the inputs and outputs for: S3, LED2, LED3 and LED4. 2. Use the wizard to make a new dsPIC30F4011 project with MPLAB. 3. In addition to the main.c file, create two files, IOSetup.c and IOSetup.h and add them to your project. Write a function in IOSetup.c that configures the I/Os for S3,LED2,LED3 and LED4 as inputs and outputs respectively. Declare this function in IOSetup.h and also #define the inputs and outputs, e.g. #define LED2Latch LATDbits.LATD1 #define LED2Port PORTDbits.RD1 4. Include IOSetup.h in main.c. Write a while(1) loop in main.c. In this while(1) loop, continuously read the switch S3 and switch on LED2 when the switch is pressed. 5. Implement a toggle functionality. When S3 is pressed the first time, LED2 is switched on. The next time you press S3 LED2 goes off (and so on). Is de-bouncing of S3 required? 6. Write a de-bouncing function. The function should measure the state of switch S3 ten times with ≈ 1ms between samples. It should return a logic ‘1’ only if all ten samples are ‘1’, otherwise the function should return ‘0’. Use the output of this function to switch or toggle LED2. 7. Toggle LED3 automatically with a rate of 5Hz when S3 is pressed. Measure this output with the scope to verify its accuracy. Take a screenshot for your log-book. 8. Implement the following two main() functions, observe the behaviour on the target and explain what happens. You can either use the port names as shown below or (better) use your own definition of the outputs as shown in the #define example above. Hint:take a closer look at the instruction cycle, consider the read-modify-write problem. (a) int main(void) 25

{ gpIOSetup(); PORTDbits.RD3=1; //sets LED3 port bit, you may use LED3Port=1; PORTDbits.RD1=1; //sets LED2 port bit, you may use LED2Port=1; while(1); return 0; //we should never really return }; (b) int main(void) { gpIOSetup(); LATDbits.LATD3=1; //sets the LED3 latch, you may use LED3Latch=1; LATDbits.LATD1=1; //sets the LED2 latch, you may use LED2Latch=1; while(1); return 0; //we should never really return }; Additionally, you can now start to explore Timer1, which is the next peripheral we will address. You can also start reading about (timer driven) interrupts. Can you blink an LED with 5 Hz using the Timer1 interrupt?

26...


Similar Free PDFs