Sie sind auf Seite 1von 17

Introduction to the PIC32: The Basics, Getting Started, IO ports and the First Program

Syed Tahmid Mahbub

Image Sources:

Cover photo http://www.flickr.com/photos/microchiptechnology/6847596741/sizes/m/in/photostream/

Fig. 1 PIC32MX250F128B datasheet Fig. 2 PIC32MX250F128B datasheet

INTRODUCTION

I have recently starting using the PIC32 series. Ive been experimenting with the Microchip Microstick II board that comes with the PIC32MX250F128B microcontroller (along with a few other non-PIC32 microcontrollers). Conveniently, the Microstick II has the microcontroller programmer on the board itself. Heres a link to the Microstick II information page: http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en556 208

From now on, the specific PIC32 microcontroller Ill be referring to will be the PIC32MX250F128B. Heres the datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/61168E.pdf

The compiler Im using is the Microchip XC32: http://www.microchip.com/pagehandler/en_us/devtools/mplabxc/

The IDE is MPLABX: http://www.microchip.com/pagehandler/en-us/family/mplabx/

In this article, Ill talk about some basics of starting with the PIC32, the IO lines, the configuration settings and a basic starting program to show all these in action. I assume that you know how to and can install the MPLABX IDE and the XC32 compiler. I also assume that you can create a new project and the necessary source file. Furthermore, I assume that you know the basics of embedded C programming and the absolute basics of microcontrollers bits, bytes, number systems, ports and registers.

PIN DESCRIPTION

Lets start by taking a look at the PIC32MX250F128B pinout:

Fig. 1 Pinout diagram of the PIC32MX250F128B

The microcontroller power supply pins are pins 8 (VSS), 13 (VDD) and 19 (VSS). With respect to VSS (which will just be grounded), VDD must be at least 2.3V and at max 3.6V for the microcontroller to operate properly: 2.3V VDD 3.6V. In most cases, VDD is chosen to be 3.3V. It is required that you use decoupling capacitors on all power lines. 100nF capacitors are recommended. These should be placed as close to the microcontroller as possible. The Microstick II board has these capacitors on the board.

For the PIC32, there is an internal core voltage regulator. To filter the output voltage of the internal voltage regulator, a capacitor is placed between VCAP (pin 20) and VSS. This capacitor should be at least 8F, but is typically 10F. The capacitor should be a low-ESR capacitor. The Microstick II board has a 10F capacitor.

Pin 28 is AVDD and pin 27 is AVSS. These are the voltage reference supplies for the internal analog-todigital converter (ADC) module. Ill covert this in a later article. But for now, you need to know that the AVDD pin must always be connected to the VDD pin, and the AVSS pin must always be connected to the VSS pin, even if the ADC module is not being used, or even if the ADC module is being used but isnt

using AVDD and AVSS. You should have at least a 100nF decoupling capacitor on the AVDD-AVSS line. On the Microstick II board, the AVDD and AVSS pins are connected to the VDD and VSS lines. The decoupling capacitor has also been placed on the Microstick II board.

As you can see, pin 1 is MCLR (Master Clear). This does the job of resetting the microcontroller. When the MCLR pin is held high, the microcontroller operates and executes the program. But when this pin is held low, the microcontroller is in a reset state where it does not execute the program. You can think of it as the microcontroller being off. When the pin is held back high, the microcontroller turns on again but starts executing the program from the very beginning again, as if it was just turned on. So, on a highto-low-to-high transition, the microcontroller is reset. There is a minimum time, however, for which the MCLR pin must be held low before being high (for reset). This minimum time is 2s.

Now, notice on the diagram that some pins are filled in gray. These are the pins that are capable of tolerating higher than 3.6V up to 5V. These pins are 5V tolerant when acting as output pins. All input pins are tolerant to 5V, so the gray-filled pins are 5V tolerant when output pins as well.

Now notice the pins that are labeled RAx and RBx (where x is a number). These are the port pins. These pins can act as inputs or outputs. All these pins are multiplexed with other peripheral modules that you can use. Ill cover these as I go to those modules in later articles.

PORT IO LINES

Each of these pins is an IO pin it can be configured for either an input or an output. The register controlling the direction of the pin whether it will be an input or an output is the corresponding bit in a TRIS register.

To make a certain pin input, the corresponding TRIS bit has to be set high. To make the pin output, the corresponding TRIS bit has to be cleared to low. The PIC32MX250F128B has two ports PORTA and PORTB. PORTA has five pins RA0, RA1, RA2, RA3 and RA4. PORTB has fifteen pins RB0 through RB5 and RB7 through RB15. Each of the ports has a corresponding TRIS register (TRISA for PORTA and TRISB for PORTB), and each of the port pins has a corresponding TRIS bit.

So lets take pin 2 RA0. This is PORT A, bit 0 (or you can call it PORTA0). The TRIS register corresponding to PORTA is TRISA. The TRIS bit corresponding to PORTA0 is TRISA0. Similarly, the TRIS bit corresponding to PORTA14 is TRISA14. To make RA0 an output, you have to clear TRISA0 to zero, and similarly, to make RA0 an input, you have to set TRISA0 to one:

TRISAbits.TRISA0 = 0; // Make RA0 an output TRISAbits.TRISA0 = 1; // Make RA0 an input

If we wanted to set all of all the PORTA and PORTB pins to outputs, then we would do:

TRISA = 0; // Make all PORTA pins output TRISB = 0; // Make all PORTB pins output

If we wanted to set all PORTA pins to inputs, and all PORTB pins to outputs, then we would do:

TRISA = 0x1F; // Make all PORTA pins input TRISB = 0; // Make all PORTB pins output

Now, notice how in the above code, I wrote TRISB to zero. This sets all the TRISB bits to zero, making all the PORTB pins to be outputs. I said before that PORTB has bits 0 through 5 and 7 through 15, but no bit 6. So, a pin RB6 doesnt exist. So, what happens when we clear TRISB6 to zero? Nothing. Its completely fine. While the physical pin RB6 doesnt exist, there is a PORTB bit 6 in the PORTB register and a TRISB bit 6 in the TRISB register. But they do nothing. But do keep in mind that no such thing as RB6 is defined for your compiler (as this doesnt physically exist). So, if you tried to do something like:

reg_ra6 = PORTAbits.RA6;

The compiler would generate an error since RA6 doesnt exist.

So, now that weve initialized the direction of the ports/pins, how do we use them?

Lets say that weve initialized all the PORTA pins to input and all the PORTB pins as outputs. So, now lets say we want to send a high to PORTB0. To write to any of the port pins, we have to write to the corresponding bits in the LAT registers. Each PORT has a corresponding LAT register and each port pin has a corresponding LAT bit. So, to write to PORTB0, we have to write to LATB0. So, to send a high to PORTB0, we would do:

LATBbits.LATB0 = 1;

Another thing to notice in the above statement is how were accessing individual bits of a register. If we were to write to bit 10 of LATB, we would do:

LATBbits.LATB10 = 1;

Alternately we could make use of another feature of the PIC32, for bit manipulation. Each of these registers has 3 other registers associated with it: a SET register, a CLR register and an INV register. These are extremely convenient for atomic bit manipulation. Instead of writing:

LATBbits.LATB10 = 1; // Set RB10 high, leave the rest unaffected

you can write:

LATBSET = 0x400; // Set RB10 high, leave the rest unaffected

What the SET, CLR and INV registers do is that, they affect only the bits that are set high, but leave those bits unaffected that are set low. So, the SET register sets to one all the PORT bits corresponding to all the bits that are set high in the SET register. The CLR register clears to zero all the PORT bits corresponding to the bits that are set high in the CLR register. The INV register inverts all the PORT bits corresponding to all the bits that are set high in the INV register.

So, lets say we initially did:

LATB = 0xFFFF; // Set all PORTB pins to high

Then, for example, to turn off/low RB10 and RB11, we could do:

LATBbits.LATB10 = 0; // Clear to low RB10, leave rest unaffected LATBbits.LATB11 = 0; // Clear to low RB11, leave rest unaffected

Or, we could do:

LATBCLR = 0xC00; // Clear RB10 and RB11, and leave the rest unaffected

Now, if we wanted to output high to all PORTB pins, we could just do:

LATB = 0xFFFF; // Turn on all PORTB pins

Now, lets look at reading digital inputs from a port pin. To read the digital state o f any pin, you need to read the corresponding PORT pin. So, if we were trying to read the state of RA2, wed just need to read the bit 2 of register PORTA. So, lets say we want to output a high on all PORTB pins if RA2 is high, wed do:

if (PORTAbits.RA2 == 1){ // If RA2 is high LATB = 0xFFFF; // Turn on all PORTB pins }

So now, youve seen how to send outputs to the PORT pins and to read digital inputs from them.

Theres one last thing we need to do before we start using the digital IO lines. Remember when I said that the PORT pins are multiplexed with other peripheral modules? These peripheral modules can mess with the PORT. Some of the PORT pins are multiplexed to the ADC module (inputs) and comparator module. So when youre trying to use those pins as digital pins, you should ensure that you configure them as digital pins. To do that, you should disable the three internal comparators and configure two ADC registers that control whether the pins are analog or digital. The three comparator registers are CM1CON, CM2CON and CM3CON. All you need to know for now is that writing these three registers to zero disables the comparators. The registers controlling the configuration of the pins as analog or digital are ANSELA and ANSELB. ANSELA controls whether PORTA pins are analog or digital, whereas ANSELB controls whether PORTB pins are analog or digital. Each of the pins (that are multiplexed to the ADC module) has a corresponding bit in the ANSEL register. So, the analog/digital set bit corresponding to RA0 would be ANSA0; that for RB13 would be ANSB13.

Now go back to the pinout diagram. You will see pins labeled as ANx (where x is an integer). These are the pins multiplexed with the ADC module (inputs) and these are the pins you need to configure as digital. For pins that are not multiplexed to the ADC, for example RB4, it doesnt matter what you write to that location (ANSELB bit 4 in this case). However, if you try to write to or read from ANSB4, youll find that this does not exist. ANSB4 is not defined and if you try to build your program, it will generate an error.

Now lets say we want to make RA0 digital. RA0 is also labeled as AN0. So, to make RA0 digital, we need to configure ANSA0. Whenever an ANSEL bit is set to one, that corresponding pin is set to be analog. So, to make RA0 digital, we need to clear ANSELA bit 0 (ANSA0) to zero. So, we do:

ANSELAbits.ANSA0 = 0;

Since in our codes we arent bothered with the ADC module at all (at least for now), we can just configure all pins to be digital. So, we do that by writing: ANSELA = 0; // PORTA pins digital ANSELB = 0; // PORTB pins digital

Similarly, we disable the comparators: CM1CON = 0; CM2CON = 0; CM3CON = 0;

FURTHER CONSIDERATIONS

Now, to complete this article, Ill have to talk a little about the oscillator in short (Ill cover the details in another article on oscillators), some functions, header files and the configuration settings before I present an example code to demonstrate what Ive talked about thus far.

For the PIC32MX250F128B oscillator, we have several options: external crystal, external resonator, external clock or internal FRC (Fast RC) oscillator. For now, Im going to use the internal FRC (Fast RC) oscillator as this means that we dont need an external oscillator.

Now lets move on to the configuration bits settings. There are certain settings that you need to define at the beginning of your code to configure the operation of your microcontroller. These are the configuration settings. You can configure them in MPLAB by setting them in Window > PIC Memory views > Configuration Bits.

I prefer setting the configuration settings in the code itself so that I know what the configuration settings are when I look at the code and for portability. If you go to Window > PIC Memory views > Configuration Bits, you can see the default settings. I made some changes for our code and here is the complete list of configuration settings. Notice how the settings are configured with #pragma. You dont need to put too much thought into this now if you dont get it. Ill cover it in more detail in a later article.

//Configuration bits settings: // DEVCFG3 // USERID = No Setting #pragma config PMDL1WAY = ON //(Allow only one reconfiguration) #pragma config IOL1WAY = ON // Peripheral Module Disable Configuration // Peripheral Pin Select Configuration (Allow

10

//only one reconfiguration) #pragma config FUSBIDIO = ON //Module) #pragma config FVBUSONIO = ON //Module) // DEVCFG2 #pragma config #pragma config #pragma config #pragma config #pragma config //by 1) FPLLIDIV = DIV_12 FPLLMUL = MUL_24 UPLLIDIV = DIV_12 UPLLEN = OFF FPLLODIV = DIV_1

// USB USID Selection (Controlled by the USB // USB VBUS ON Selection (Controlled by USB

// // // // //

PLL Input Divider (12x Divider) PLL Multiplier (24x Multiplier) USB PLL Input Divider (12x Divider) USB PLL Enable (Disabled and Bypassed) System PLL Output Clock Divider (PLL Divide

// DEVCFG1 #pragma config FNOSC = FRC //(FRC)) #pragma config FSOSCEN = ON #pragma config IESO = OFF #pragma config POSCMOD = OFF //osc disabled) #pragma config OSCIOFNC = OFF //(Disabled) #pragma config FPBDIV = DIV_8 //Sys_Clk/8) #pragma config FCKSM = CSDCMD //(Clock Switch Disable, FSCM Disabled) #pragma config WDTPS = PS1048576 #pragma config WINDIS = OFF //Timer is in Non-Window Mode) #pragma config FWDTEN = OFF //Bit Controls)) #pragma config FWDTWINSZ = WISZ_25 //25%) // DEVCFG0 #pragma config #pragma config //PGEC1/PGED1) #pragma config #pragma config //Disabled) #pragma config JTAGEN = OFF ICESEL = ICS_PGx1 PWP = OFF BWP = OFF CP = OFF

// Oscillator Selection Bits (Fast RC Osc // Secondary Oscillator Enable (Enabled) // Internal/External Switch Over (Disabled) // Primary Oscillator Configuration (Primary // CLKO Output Signal Active on the OSCO Pin // Peripheral Clock Divisor (Pb_Clk is // Clock Switching and Monitor Selection // Watchdog Timer Postscaler (1:1048576) // Watchdog Timer Window Enable (Watchdog // Watchdog Timer Enable (WDT Disabled (SWDTEN // Watchdog Timer Window Size (Window Size is

// JTAG Enable (JTAG Disabled) // ICE/ICD Comm Channel Select (Communicate on // Program Flash Write Protect (Disable) // Boot Flash Write Protect bit (Protection // Code Protect (Protection Disabled)

In the configuration settings, Ive set the oscillator to be the internal FRC (Fast RC) oscillator. The FRC (Fast RC) oscillator is set to 8MHz but the system clock is 4MHz by default. Why is that, and how can we change the FRC (Fast RC) oscillator frequency? We need to take a look at the OSCCON register. Read on in the next page.

11

Fig. 2 OSCCON register

The FRC (Fast RC) oscillator frequency is 8MHz and thats set in the PIC. But the system clock is not necessarily equal to the FRC (Fast RC) oscillator frequency. It is actually equal to the FRC oscillator frequency divided by a certain number, as set by the FRCDIV bits in the OSCCON register (bits 24, 25 and 26). Ive shown these bits in the diagram above.

So, you can see in the diagram that the default divider value is 2. Thats why the default system clock is 4MHz. If we change the default value to 1, we can have a system clock of 8MHz. If we change the divider value to 8, then the system clock will be 1MHz. And so on.

The other bits I want to talk about here are the PBDIV bits (bits 19 and 20). These set the peripheral bus clock. The peripheral bus clock is the clock to the peripherals (for example, the timers, the ADC module,

12

etc.) in the PIC. The default value is system clock divided by 8. We can change this by writing 0 to PBDIV (bits 19 and 20). We can also change this by altering one of the configuration bit settings:

#pragma config FPBDIV = DIV_8 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/8) to #pragma config FPBDIV = DIV_1 // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)

Now on to the header files. All the register descriptions, essential definitions, etc are defined in the specific devices header file. You can add this header file called p32xxxx.h which will include the required header file for your device (determining using the device you selected in project settings). So all you need to do is just add the p32xxxx.h header file.

There are a lot of macros and functions for different peripherals of the PIC32 that we can take advantage of. To do that, we have to include the relevant library header files. Instead, we can just add the header file plib.h that will include the peripheral header files.

We add the two header files as:

#include <p32xxxx.h> #include <plib.h>

There are certain features of the PIC32 that can be configured for maximum performance at the given clock. We can do this all manually (I wont cover that al here), but instead we can simply just use a library function that will do that for us:

SYSTEMConfigPerformance(8000000L); // Configure system for max performance for 8MHz

For this function, the header file plib.h must be included.

13

So, the basic code layout for my code looks like:

/* * File: * Author: * * Created * * Program * */ main.c Syed Tahmid Mahbub on description:

// Insert the configuration settings here. Im not including them here for conciseness and readability

#include <p32xxxx.h> #include <plib.h> void main(void) // same as main() { // Configure clock OSCCONbits.FRCDIV = 0; // 8MHz OSCCONbits.PBDIV = 0; // 8Mhz for peripherals // Configure system for max performance SYSTEMConfigPerformance(8000000L); // Disable watchdog timer WDTCON = 0; // do further initializations, as required while (1){ // do tasks } }

14

FINAL CODE

Now, lets look at our final code to light an LED that is connected to RA0 (the Microstick II board has a red LED connected to RA0). Here Ive applied all (or at least most) of what Ive talked about above.
/* * File: * Author: * * Created * * Program */ main.c Syed Tahmid Mahbub on 04 November 2013 description: Light an LED that is connected to RA0

#include <p32xxxx.h> #include <plib.h> // Configuration bits set in Window > PIC Memory views > Configuration Bits // Source code generated there and pasted here for readability/portability //Configuration bits settings: // DEVCFG3 // USERID = No Setting #pragma config PMDL1WAY = ON //(Allow only one reconfiguration) #pragma config IOL1WAY = ON //only one reconfiguration) #pragma config FUSBIDIO = ON //Module) #pragma config FVBUSONIO = ON //Module) // DEVCFG2 #pragma config #pragma config #pragma config #pragma config #pragma config //by 1) FPLLIDIV = DIV_12 FPLLMUL = MUL_24 UPLLIDIV = DIV_12 UPLLEN = OFF FPLLODIV = DIV_1 // Peripheral Module Disable Configuration // Peripheral Pin Select Configuration (Allow // USB USID Selection (Controlled by the USB // USB VBUS ON Selection (Controlled by USB

// // // // //

PLL Input Divider (12x Divider) PLL Multiplier (24x Multiplier) USB PLL Input Divider (12x Divider) USB PLL Enable (Disabled and Bypassed) System PLL Output Clock Divider (PLL Divide

// DEVCFG1 #pragma config FNOSC = FRC //(FRC)) #pragma config FSOSCEN = ON #pragma config IESO = OFF #pragma config POSCMOD = OFF //osc disabled) #pragma config OSCIOFNC = OFF //(Disabled) #pragma config FPBDIV = DIV_8 //Sys_Clk/8)

// Oscillator Selection Bits (Fast RC Osc // Secondary Oscillator Enable (Enabled) // Internal/External Switch Over (Disabled) // Primary Oscillator Configuration (Primary // CLKO Output Signal Active on the OSCO Pin // Peripheral Clock Divisor (Pb_Clk is

15

#pragma config FCKSM = CSDCMD //(Clock Switch Disable, FSCM Disabled) #pragma config WDTPS = PS1048576 #pragma config WINDIS = OFF //Timer is in Non-Window Mode) #pragma config FWDTEN = OFF //Bit Controls)) #pragma config FWDTWINSZ = WISZ_25 //25%) // DEVCFG0 #pragma config #pragma config //PGEC1/PGED1) #pragma config #pragma config //Disabled) #pragma config JTAGEN = OFF ICESEL = ICS_PGx1 PWP = OFF BWP = OFF CP = OFF

// Clock Switching and Monitor Selection // Watchdog Timer Postscaler (1:1048576) // Watchdog Timer Window Enable (Watchdog // Watchdog Timer Enable (WDT Disabled (SWDTEN // Watchdog Timer Window Size (Window Size is

// JTAG Enable (JTAG Disabled) // ICE/ICD Comm Channel Select (Communicate on // Program Flash Write Protect (Disable) // Boot Flash Write Protect bit (Protection // Code Protect (Protection Disabled)

// 8MHz internal Fast RC oscillator selected // System clock cycle = 125ns when system clock = 8MHz main(){ // Configure clock OSCCONbits.FRCDIV = 0; // 8MHz OSCCONbits.PBDIV = 0; // 8Mhz for peripherals // Configure system SYSTEMConfigPerformance(8000000L); // Configure system for max performance // Disable watchdog timer WDTCON = 0; // Disable comparators: CM1CON = 0; CM2CON = 0; CM3CON = 0; // Configure pins to be digital: ANSELA = 0; // Make all PORTA pins digital ANSELB = 0; // Make all PORTB pins digital // Initialize PORT direction: TRISA = 0; // Make all PORTA pins output // Start: LATAbits.LATA0 = 1; // Turn on LED at RA0 while (1) { // LED has been turned on. Do nothing now } }

16

CONCLUSION

Here I end this article. In the next article, Ill talk a little bit more about the IO lines including reading inputs from switches (Ill present an example of using the IO lines as inputs), using the pull-ups and pulldowns. Ill also explain the code for blinking an LED, and in the process explain the very important Core Timer of the PIC32MX250F128B and how to create time delays with it.

In this article, Ive talked about some basics of the PIC32MX250F128B, getting started with it, using the IO lines, the initial necessary header files and configuration settings. I hope you have found this helpful. Let me know what you thought in the comments section. Feel free to ask any questions or provide any suggestions you may have.

17

Das könnte Ihnen auch gefallen