Tuesday, 6 August 2013

PIC32's : Some basics


*PIC32MX250F128B's datasheet is the same as PIC32MX110F016B
Among the many features available on a PIC32, to chose from, we should maybe start with the basic port operations...
On the Microchip datasheet (1), we can read the following, about some of the the key features of the I/O Ports module:
• Individual output pin open-drain enable/disable
• Individual input pin pull-up enable/disable
• Monitor select inputs and generate interrupt on mismatch condition
• Operate during CPU Sleep and Idle modes
• Fast bit manipulation using CLR, SET and INV registers ( mentioned previous article- see below).

Before reading and writing any I/O port, the correct registers of the desired pins should be properly configured .
Each I/O port has nine registers directly associated with the operation of the port and one control register. Each I/O port pin has a corresponding bit in these registers. Throughout this section, the letter ‘x’, refers to relevant port module ( TRISA, TRISB, TRISC, etc).
NOTE: Any bit and its associated data and control registers that is not valid for a particular device will be disabled and will read as zeros.

TRISx registers configure the data direction through port  pins; in other words, it determines whether a port pin is an input or an output:
If data direction bit is ‘1’, the pin is an input; If data direction bit is ‘0’, the t pin is an output
A read from a TRISx register reads the last value written to the TRISx register
* to note that all I/O pins are defined as inputs after a Power-on Reset
A write to a PORTx register writes to the corresponding LATx register (PORTx data latch).
Those I/O port pin(s) configured as outputs are updated.
The datasheet refers to the fact that a write to a PORTx register is the effectively the same as a write to a LATx register; they also note that a read from a PORTx register reads the synchronized signal applied to the pins
LATx registers act as PORTx data latch, and hold the data written to port I/O pin(s):
A write to a LATx register latches data to corresponding port I/O pins. And only those port pins configured as outputs are updated.
A read from LATx register reads the data held in the PORTx data latch, not from the port
 pins themselves.

You should check the file p32mx250f128b.h for a list of all definitions  names of the  Special-Function Registers (SFRs) of the device.
Inside, we can expect something like this( Port A basic registers as example):

 __TRISAbits_t;
extern volatile __TRISAbits_t TRISAbits __asm__ ("TRISA") __attribute__((section("sfrs")));
extern volatile unsigned int        TRISACLR __attribute__((section("sfrs")));
extern volatile unsigned int        TRISASET __attribute__((section("sfrs")));
extern volatile unsigned int        TRISAINV __attribute__((section("sfrs")));
extern volatile unsigned int        PORTA __attribute__((section("sfrs")));
typedef union {
  struct {
    unsigned RA0:1;
    unsigned RA1:1;
    unsigned RA2:1;
    unsigned RA3:1;
    unsigned RA4:1;
  };
  struct {
    unsigned w:32;
  };
} __PORTAbits_t;
extern volatile __PORTAbits_t PORTAbits __asm__ ("PORTA") __attribute__((section("sfrs")));
extern volatile unsigned int        PORTACLR __attribute__((section("sfrs")));
extern volatile unsigned int        PORTASET __attribute__((section("sfrs")));
extern volatile unsigned int        PORTAINV __attribute__((section("sfrs")));
extern volatile unsigned int        LATA __attribute__((section("sfrs")));
typedef union {
  struct {
    unsigned LATA0:1;
    unsigned LATA1:1;
    unsigned LATA2:1;
    unsigned LATA3:1;
    unsigned LATA4:1;
  };
  struct {
    unsigned w:32;
  };
} __LATAbits_t;
extern volatile __LATAbits_t LATAbits __asm__ ("LATA") __attribute__((section("sfrs")));
extern volatile unsigned int        LATACLR __attribute__((section("sfrs")));
extern volatile unsigned int        LATASET __attribute__((section("sfrs")));
extern volatile unsigned int        LATAINV __attribute__((section("sfrs")));
extern volatile unsigned int        ODCA __attribute__((section("sfrs")));
typedef struct {
  unsigned w:32;
}

So lets start with some basic code.
First, i would advise you with the priceless tool that is the Sim included in MPLab and MPLab X.

#include < p32xxxx.h >
/*
* We could include p32mx250f128b.h directly, but this way we make the code more  
* portable. 
*/
main()
{
int a;

#ifndef PIC32_STARTER_KIT
     /*The JTAG is on by default on POR.  A PIC32 Starter Kit uses the JTAG, but
     for other debug tool use, like ICD 3 and Real ICE, the JTAG should be off
     to free up the JTAG I/O */
     DDPCONbits.JTAGEN = 0;
  #endif

// init the needed registers:
TRISA = 0xff00; // PORTA pin 0..7 as output
    //  main loop:
while(1){
a=256;     // Variable to waste time
while (a --){
// While variable a decrements, we keep pin 0 on, for debug purposes
PORTA = 0x0001;     // turn pin 0 on
}
PORTA = 0; /* turn all pins off; notice that, without 0x prefix, the compiler assumes the default decimal radix */
}
}

From the previous article, we can remember the following :The PIC32  brings also a set of registers called SET, CLEAR, and INVERT.
When you write to any of these registers, the PIC32 performs the read-modify-write operation in a single clock, allowing  the ability to quickly manipulate I/O ports and bits.  This means that, you can toggle any general purpose I/O pin at the SYSCLK speed! This atomic bit manipulation capability means that  the SET, CLR, and INV operations cannot be interrupted.
For example, the LATA SFR is followed by LATACLR, LATASET, and LATAINV.  To clear a group of bits in the LATA register, you would write the corresponding mask values into the LATACLR register.
Similarly, a  write to the SET register would set the corresponding bits and a write to INV register would toggle the bits..
This of course, makes basic port operations much easier, as we can see from the next example !
So lets put it into practice
/*
Example 2
*/
#include < p32xxxx.h >

main() 
{
#ifndef PIC32_STARTER_KIT
     /*The JTAG is on by default on POR.  A PIC32 Starter Kit uses the JTAG, but
     for other debug tool use, like ICD 3 and Real ICE, the JTAG should be off
     to free up the JTAG I/O */
     DDPCONbits.JTAGEN = 0;
  #endif
 LATACLR  = 0x0001;     // RA0 Off  
 TRISACLR = 0x0001;     // RA0 as output  
      while(1)    
    {
LATAINV = 0x0001;// toggle RA0   
Nop();     //Kill time.
    }

No comments:

Post a Comment

Feel free to contact me with any suggestions, doubts or requests.

Bless