www.allpcb.com

Author Topic: PIC32MX Quickstart - A Tutorial for Hobbyists  (Read 51657 times)

0 Members and 1 Guest are viewing this topic.

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
PIC32MX Quickstart - A Tutorial for Hobbyists
« on: May 18, 2012, 10:19:59 AM »
PIC32MX Quickstart

The  Motivation


I recently acquired a sample quantity of PIC32MX150F128B Chips and am very pleased with them. They contain an impressive set of peripherals, several of which are not available in the 8 bit chips, they have the same MIPS M4K Core as the larger members of the PIC32MX family, so code is portable between them all, and whilst cheaper than several of the 8 and 16 bit chips they provide full 32bit arithmetic, have a staggering amount of Flash and RAM compared to the 8 Bit chips and they can run at 40Mhz. 

The real clincher for me is that they also come in a 28 Pin DIP package (Skinny DIP, The long slim through hole IC Packaging, not swimming naked) which is perfect for hobbyists because they can be used on a standard breadboard. That makes them accessible without having to buy a full development kit. (You will have to buy a programmer if you don’t already have a suitable one, but that may well be a better long term investment than the Development Kit.)
In short they are a perfect introduction to the world of 32 Bit Microcontrollers, C Programming, MIPS Processors and technologies like capacitive touch sensing, Digital Signal Processing and low power architectures and techniques.

BUT they are still usable and affordable in most applications that a hobbyist would use an older 8 Bit PIC.

The Reason for this Tutorial

Whilst fairly easy to setup they are new enough that very little practical information is available on the internet to help Hobbyists get started and they are different enough from the PIC16’s and ATMega’s that there are many “Traps for Young Players” as a famous Video Blogger would say.


Having previously worked with the larger PIC32 chips I thought I would help fill that gap, and contribute something back to the community,  with a simple Breadboard Circuit, some Sample Source Code and some narrative to help navigate the initial mine field. It is intended to provide you with a Quickstart that you can then modify, expand or even replace once you gain confidence with the chip.

Both the Code and the Circuit should work with any PIC32MX1 or 2 series Chip in a SPDIP 28 Package, but I have only tested it with the MX150.

At a later stage I hope to develop a Bootloader for them as well, but for now you will need at least a PICKit3 to program them and a TTL Level FTDI cable or adapter to use the Serial Communications.

The accompanying Source Code addresses the basics of:
  • Setting the Configuration Fuses and Clock Source.
  • Optimizing performance
  • Creating a 1mS interrupt from the MIPS Core Timer.
  • Mapping a Peripheral (UART2) to I/O Pins using Peripheral Pin Select (PPS).
  • Configuring the UART
It also provides a simple set of Utilities for Serial Communications and a Simple “Hello World!” test application to show that it all works as expected.

I will post this project as a series of parts so this is Part 1 of Several.

The next post will be the hardware section

Cheers

Chris
« Last Edit: May 19, 2012, 10:51:30 PM by caroper »
 

Offline BloodyCactus

  • Frequent Contributor
  • **
  • Posts: 439
  • Country: us
Re: PIC32MX Quickstart
« Reply #1 on: May 18, 2012, 11:03:04 AM »
sounds good. can you use the bootloader from ubw32?  I know the chipkit stuff has alternate usb bootloader and an arduino style bootloader... maybe one of those would work?
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart
« Reply #2 on: May 18, 2012, 11:27:59 AM »
The two you suggest are both good examples of working Bootloaders, however, the only one I have any experience with is the the ChipKit bootloader and that is based on the AVRDude format. To work with MPLAB you need a bootloader that can handle Intel Hex16 format.

I recently created one for a client, so that is the one I will port over for this project, but I agree that a Chipkit Bootloader would be awesome. It would also need a lot of other support work in order to work with MPIDE though, so I think that is more a ChipKit community project than a Hobbyist intro to PIC32MX.


Cheers
Chris



Offline T4P

  • Super Contributor
  • ***
  • Posts: 3706
  • Country: sg
    • T4P
Re: PIC32MX Quickstart
« Reply #3 on: May 18, 2012, 05:00:35 PM »
But ... there are teething problems on the PIC32 i read up on microchip's forums before. TEETHING.
http://the4thpin.comeze.com <-- Rants and Reviews! sorry my english  :palm:
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart
« Reply #4 on: May 18, 2012, 06:27:27 PM »

PIC32MX Quickstart

Part One - Hardware:


Introduction:
The Hardware could not be any simpler. In fact you can plug the chip into a breadboard, connect it to a PICKit3 (with no external components) and have a working system. There are, however, certain recommendations that the manufacturer (Microchip) give for reliability and stability of the circuit. 

The Datasheet for the chips is available here PIC32MX1XX/2XX Family Data Sheet I suggest you grab a copy to read along and help you expand on this basic introduction and to get a better overview of the chips capabilities.

Section 2.0 of that document recommends (in fact insist on)  Decoupling Capacitors on ALL supply pins (Analogue and Digital) and a Capacitor on the Internal Voltage regulator, even if the regulator is not being used. It also shows how to protect the Reset (MCLR) pin to prevent accidental resets.

Here is the schematic for my breadboard circuit.


Notes on the Schematic:
  • The 3x  0.1uF capacitors are Ceramics

  • The 10uF capacitor is a Tantalum 6V rating but I used a 10V 6.8uF from the parts box.

  • There is NO Oscillator Circuit. The Clock is generated onboard.

  • There is NO Voltage regulator, I power the circuit from the PICKit3 or the FTDI Board.
CAUTION: These Chips are 3V3 parts, DO NOT Power them from a 5V FTDI Cable (Use a  Bench Supply or a 3v3 low dropout regulator if a 5V FTDI cable is all you have). I use the Adafruit FTDI Friend: https://www.adafruit.com/products/284 It has jumpers that allow you to change Vcc and the Signal Levels from 5V (default) to 3V3. DO NOT Connect Vcc to Vdd unless you have modified the FTDI Friend or have a 3V3 FTDI.

Do Not have both the PICKit3 and the FTDI powering the circuit at the same time.
The PICKit3 Power is off by default. If you wish it to Power the Circuit, you have to turn the option on in the IDE. It is intelligent enougth to detect that the Circuit it already powered but for the sake of an expensive piece of kit I still suggest you be selective. If you have a 3v3 FTDI or an external 3V3 supply then use that and leave it connected.

The Pins that have been chosen to act as Rx and Tx on the Chip were selected specifically because they are are 5V tolerant, so any TTL level FTDI cable should work (excluding Vcc). I have tested it with the FTDI Friend in 5V mode and all was well.

I have Labeled the Pins for what they are being used for, you will not find pins marked as Rx and Tx in the Datasheet, they are assigned using Peripheral Pin Select (PPS).


 The Breadboard Layout:




Notes on the Layout:
  • Notice that all of the Capacitors are as close as possible to the pins they are Decoupling and that the wires are as short as possible. This chip is running at 40MHz which is really pushing the limits for a breadboard circuit. Fortunately because we are using an internal Clock the maximum frequency we see externally will be 8MHz (Explained later).

  • I have tried to keep the layout compact so that it can be built on a Mini Breadboard too. It also leaves 2/3 of a standard breadboard free for application circuits that way.

  • You will notice one extra component that I didn’t show on the Schematic, it is a 22uF 50V electrolytic, across the supply rails. I added it as a tank circuit to relieve the load on the PICKit3 whilst Flashing LED’s. It is not strictly needed but probably helps.
  • On my breadboard I removed the upper power strip. I makes it easier to use right angle connectors for the PICKit3 and the FTDI Friend, but you can leave it intact and use vertical connectors and a ribbon cable to connect if you prefer.
That is it for now, I have begun to build it on a small piece of strip board along with a regulator and some common support circuits, such as those found on development boards. I will post that as a separate hardware section though.

The Above is all you need to get started and you have the rest of your breadboard available for building support circuits.

Next Up - Software - Framework.

Cheers
Chris
« Last Edit: May 19, 2012, 09:46:38 AM by caroper »
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart
« Reply #5 on: May 18, 2012, 08:10:07 PM »

PIC32MX Quickstart

Part Two - Software:

Preamble:


You will need MPLab to experiment with the Chip.

I have developed the code with MPLAB 8.x and C32 V2.2 under Windows XP. There is no reason, however, for it not to work with MPLabX on any other Platform (WIN7, MacOS and Linux included).

The reason I am still using MPLAB 8.x, (apart from not having the time or inclination to learn yet another IDE) is that I am working on a large project that started in MPLAB 8.x and all the other team members are using MPLAB 8.x.  So for the sake of sanity and to ensure we don't inadvertently change anything at this late stage of a year long project, we chose to remain on MPLAB 8.x until the Project is signed off.

Both are available FREE from Microchip, MPLAB 8.x is here and MPLABX is here


Download and install the one you prefer or that supports your computer, but remember I can only advise on MPLAB 8.x at this stage if you get stuck and any posted screen shots will be from MPLAB 8.x.

Testing the circuit - Our First Code:

One of the things I really like about this family of chips is the flexibility they provide in terms of Oscillator selection. 
However, along with choices comes complexity and the first hurdle to overcome with any Microcontroller is to get it to clock.


This can be even more difficult to achieve on a breadboard due to all the parasitic capacitance and inductance floating around.


Fortunately Microchip took that into account when designing this chip so the default Oscillator is an internal High Speed RC clock running at 8MHz.


You can plug in the chip, apply 3V3 and it runs.


Here is the absolute minimum code needed to flash the LED.

Code: [Select]
// Example 1.0

#include <plib.h>

main()
{
    mPORTAClearBits(BIT_0);           //Clear bits to ensure the LED is off.
    mPORTASetPinsDigitalOut(BIT_0);   //Set port as output

    int j;

    while(1)   
    {
        j = 100000;
        mPORTAToggleBits(BIT_0);      //Toggle light status.
        while(j--) {}                 //Kill time.
    }
}

That is all you need to prove that you have correctly wired the Board, programmed the chip and everything is running.

The next section will start to go into more detail, take a look at the Configuration and Fuse settings and show how to setup the Clock Frequency to get the maximum number of MIPS (Pun Intended) from our MIPS M4K Core.

Cheers
Chris
 
Edited to implement advice from baljemmett
« Last Edit: May 19, 2012, 09:00:55 AM by caroper »
 

Offline nctnico

  • Super Contributor
  • ***
  • Posts: 11478
  • Country: nl
    • NCT Developments
Re: PIC32MX Quickstart
« Reply #6 on: May 18, 2012, 10:15:48 PM »
But ... there are teething problems on the PIC32 i read up on microchip's forums before. TEETHING.
Can you elaborate on that?
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline baljemmett

  • Supporter
  • ****
  • Posts: 666
  • Country: gb
Re: PIC32MX Quickstart
« Reply #7 on: May 18, 2012, 10:39:45 PM »
Because the Forum Editor (Not Dave, the Software) has a nasty tendancy to keep mangeling anything I paste in, the code is also attached as example 1.0.c.txt - You will have to remove the .txt portion to use this in MPLAB, it is only there because of the Editor not accepting .c files as attachments.

The forum will co-operate a bit more if you put your code inside code tags -- [ code ] ... [ /code ], without the spaces -- that gives you a properly formatted box with scrollbars and an easy way to copy the text, as follows:

Code: [Select]
// Example 1.0

#include <plib.h>

main()
{
    mPORTAClearBits(BIT_0);           //Clear bits to ensure the LED is off.
    mPORTASetPinsDigitalOut(BIT_0);   //Set port as output

    int j;

    while(1)   
    {
        j = 100000;
        mPORTAToggleBits(BIT_0);      //Toggle light status.
        while(j--) {}                 //Kill time.
    }
}

... and now I'm wondering whether I should upgrade my ancient PICkit so I can try one of these new-fangled devices out ;)
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart
« Reply #8 on: May 18, 2012, 10:56:38 PM »
Thanks for that, it will be a great help :)


Unfortunately, whilst the PICKit2 version V2.61 supports a few of the PIC32 Chips, it does not support the PIC32MX1xx range.


The chips were only announced in January and have only started shipping in production quantities fairly recently.
So before you replace the trusty old PICKit2 it may be worth asking Microchip if they have an update in the pipeline to support the MX1xx series.


Even if you do replace the PICKit2 with the PICKit3 hang on to it.
I have found the Serial Communications and the Simple Logic Analyzer functions invaluable in the past.
In fact this Project may be a perfect use for those features :)


Cheers
Chris


Offline T4P

  • Super Contributor
  • ***
  • Posts: 3706
  • Country: sg
    • T4P
Re: PIC32MX Quickstart
« Reply #9 on: May 19, 2012, 12:37:02 AM »
http://the4thpin.comeze.com <-- Rants and Reviews! sorry my english  :palm:
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart
« Reply #10 on: May 19, 2012, 01:23:05 AM »
http://www.microchip.com/forums/m586823.aspx

I am not sure of the relevance of the link Dave?
It is talking about the dsPIC33E (PIC24H) architecture.
This thread is about the MIPS Based PIC 32 Architecture. They are totally different families of chips.


Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart
« Reply #11 on: May 19, 2012, 04:56:12 AM »

PIC32MX Quickstart
Part Three - Configuration:

Clock Management:

As mentioned earlier The PIC32MX has a very flexible Oscillator section including four external and internal oscillator options as clock sources, combined with an On-Chip PLL with user-selectable input divider, multiplier and output divider to boost operating frequency of the selected sources.

Our initial test code is using the internal RC oscillator at its default frequency.
Whilst sufficient to get the chip up and running or even to run non time critical applications, an RC clock is not stable or accurate enough for any kind of communications, or so I thought.

Let’s take a look at FIGURE 8-1: of the PIC32MX1XX/2XX Family Data Sheet  (I linked to it before so you may not need to download it again). The first thing that I noticed is that the Chip actually has two PLL systems. one for the system Clock and another one for the USB clock. But what I found really surprising is that the RC Oscillator (FRC) is connected to the input of the PLL.

Experiment 1.

Seeing that the FRC is connected to the PLL and the chip is capable of running at 40Mhz, lets have a look at what is required to set up the PLL.

Referring again to the Datasheet FIGURE 8-1 we can see that the PLL input can be selected as either Posc or FRC and that the input needs to be between 4 and 5 Mhz. We also know that our FRC Oscillator is running at 8MHz so the first thing we need to do is divide the Clock by 2. There is no Multiply by 10 function but there is a Multiply by 20 so in order to get a 40MHz output all we need to do now is Divide that by 2 again.

All of those steps are set by the Configuration Bits or Fuses.

For a full list of configuration bits, in MPLab, select Help --> Topics...
From the list select  Language Tools --> PIC32MX Config Settings.
Finally from the list of devices select PIC32MX150F128B (Or the Chip that you are using)

I will not go into detail here, I just wanted to show you where to find them, as that is one of the most frequently asked questions.

The Fuses, or Configuration Bits are set in C32 by using the #pragma config derivative.

Lets have a look at what we need to select our FRC as input to the PLL, from the list we find Oscillator Selection Bits and within that FNOSC = FRCPLL
Now we need the PLL Input Divider: FPLLIDIV = DIV_2
Our Multiplier: FPLLMUL = MUL_20
and finally the System PLL Output Clock Divider FPLLODIV = DIV_2

Putting it all together we get:

#pragma config   FNOSC = FRCPLL
#pragma config   FPLLIDIV = DIV_2
#pragma config   FPLLMUL = MUL_20
#pragma config   FPLLODIV = DIV_2

Those could be combined into one line as :

#pragma config FNOSC = FRCPLL, FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPLLODIV = DIV_2

They can also be in any order, However, I don’t recommend doing that as it is easy to end up spending hours trying to find a non existent bug in your code when in reality you have just overlooked a fuse setting. You will be thankful one day if you have them one per line and in a logical order.

Modifying our example code we get:

Code: [Select]
// Example 2.0

#pragma config   FNOSC       = FRCPLL
#pragma config   FPLLIDIV    = DIV_2
#pragma config   FPLLMUL    = MUL_20
#pragma config   FPLLODIV    = DIV_2

#include <plib.h>

main()
{
    mPORTAClearBits(BIT_0);           //Clear bits to ensure the LED is off.
    mPORTASetPinsDigitalOut(BIT_0);   //Set port as output

    int j;

    while(1)   
    {
        j = 100000;
        mPORTAToggleBits(BIT_0);      //Toggle light status.
        while(j--) {}                 //Kill time.
    }
}

Upload it to the chip and you will see the LED Flash rate increase dramatically.

If you have a frequency counter you could measure the rate before and after by measuring the output of RA0.
Using the EXETECH I measured 1.542Hz initially and 15.42Hz after the  Oscillator modifications for an exact 10 fold increase in performance.

Experiment 2.

We still have not quite finished with our Oscillator set up. You will also notice from Datasheet FIGURE 8-1 That the Peripheral Bus has a separate Clock (PBCLK) that is derived from the system clock. As we are trying to get the maximum we can out of the Chip, let's set the PBCLK to 40Mhz too: #pragma config   FPBDIV = DIV_1


The chip has a lot of registers that can be used to optimize the internal pipe lining of the chip. Without going into too much detail suffice it to say we have DMA controllers that are running independently from the Peripheral Bus and the CPU, we also have various wait states on certain memory locations such as the Flash, the Ram and the Internal Registers, we also have several other factors such as instruction and data pipe lining that can impact on performance.


The topic of optimization is sufficient to fry your brain, well mine at least, and it could certainly put the hobbyist off using such a powerful chip. Fortunately we don't have to worry about it. You will have noticed that in our code we have the statement:

#include <plib.h>

Plib is a Library of macros and functions specifically designed to make it easier to use the PIC32 Chips.
One of the most useful Functions in it is the System Configuration utility so lets put it to use.

System Optimization

In order to use it we need to pass it our clock frequency, but as  several functions in Plib also require that information it is useful to define it in one place and use it wherever we need it. That way if we change our Clock Frequency to reduce power consumption for instance, we only ever change it in one place.

#define GetSystemClock()       (40000000ul)

notice that although 40000000 is a constant we need to type it as an unsigned long hence the ul postfix.

we are running our
Peripheral Bus at the same speed so we also define:

#define GetPeripheralClock()    (GetSystemClock())

Then in the initialization part of our code we can say:

SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

Putting it all together we now get:


Code: [Select]
// Example 2.1

#pragma config   FNOSC       = FRCPLL
#pragma config   FPLLIDIV    = DIV_2
#pragma config   FPLLMUL    = MUL_20
#pragma config   FPLLODIV    = DIV_2
#pragma config   FPBDIV       = DIV_1

#define GetSystemClock()       (40000000ul)
#define GetPeripheralClock()    (GetSystemClock())

#include <plib.h>

main()
{
   SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

    mPORTAClearBits(BIT_0);           //Clear bits to ensure the LED is off.
    mPORTASetPinsDigitalOut(BIT_0);   //Set port as output

    int j;

    while(1)   
    {
        j = 100000;
        mPORTAToggleBits(BIT_0);      //Toggle light status.
        while(j--) {}                 //Kill time.
    }
}


Compile, and upload it and you will notice another change in the flash rate.

If you still have the Frequency Counter attached it will be reading somewhere around 20Hz, 20.05 in my case.
So that one line of code has given us another 25% increase in performance.
Certainly a function worth having.


That is it for today, but I will continue tomorrow with a look at Peripheral Pin Select (PPS) and Setting up a UART for serial communications.


Till then,
Cheers,
Chris
« Last Edit: May 20, 2012, 07:41:12 PM by caroper »
 

Offline BloodyCactus

  • Frequent Contributor
  • **
  • Posts: 439
  • Country: us
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #12 on: May 19, 2012, 11:55:00 AM »
this is awesome! thanks mate.
 

Offline T4P

  • Super Contributor
  • ***
  • Posts: 3706
  • Country: sg
    • T4P
Re: PIC32MX Quickstart
« Reply #13 on: May 19, 2012, 02:01:49 PM »
http://www.microchip.com/forums/m586823.aspx

I am not sure of the relevance of the link Dave?
It is talking about the dsPIC33E (PIC24H) architecture.
This thread is about the MIPS Based PIC 32 Architecture. They are totally different families of chips.

They have been talking about the PIC32, scroll down.
http://the4thpin.comeze.com <-- Rants and Reviews! sorry my english  :palm:
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #14 on: May 20, 2012, 10:26:17 AM »
PIC32MX Quickstart

Part 4 - Peripheral Pin Select (PPS)

Anyone starting out with the MX150, that is used to working with other chips, are likely to look at the pin out diagram and think it has hardly any peripherals. They couldn't be more wrong.

One of the biggest problems with microcontrollers is how to bring all of the peripherals out to pins without making them mutually exclusive, for instance if the SPI module and the Timer/Counter module share a common pin, you can use one or the other but not both.

Things get even worse the less pins you have to work with and the MX150 only has 28 PINS.
To compound the issue further this chip packs a lot of Peripherals but only 21 of the 28 Pins are usable for actual I/O.
This sounds like a recipe for disaster, but it is not thanks to PPS.

Lets have a look at it, you will need the PIC32MX1XX/2XX Family Data Sheet again. Download it if you haven't already.

TABLE 11-1: of the Datasheet shows the possible INPUT PIN SELECTION and TABLE 11-2: the OUTPUT PIN SELECTION.

At first glance these look pretty daunting. You can either select a Peripheral and see which pins it can use or you can select a pin and see which peripherals are available. The tables are also separated into 4 groups of 8 Pins.
For Inputs the the Peripheral is listed on the left and the available pins on the right.
For outputs it is the other way round.


So lets have a look at how these tables are used.

Possibly the most used peripheral in any microcontroller is the UART.

Even if the target application has no need to talk to a PC, having some kind of console I/O is incredibly useful for debugging. Often when I have the ICD3 and the Logic / Protocol analyzer connected I still have a console session going at the same time. So lets have a look at connecting a UART to the outside world via PPS.

The MX150 has two UART’s so lets have a look and see where we can connect them.

First we will consider UART1 so we look at TABLE 11-1 Left hand column and look for U1RX.

We find that RPA2, RPB6, RPA4, RPB13, RPB2, RPC6, RPC1 and RPC3 can all be used.

Next we locate them physically on the package, to do this you need to cross reference the pinout diagram on page 4. (I always print out the diagram for the package I am working with).

At this point we can see a problem with using UART1 in this application.

The dark shaded PINS on the diagram are 5V tolerant, but none of the available pins for U1RX fall in this category. This interface is likely to be used with a 5V FTDI cable so a 5V tolerant input is essential.

Lets have a look for U2RX instead. We find it can be used on RPA1, RPB5, RPB1, RPB11, RPB8,  RPA8, RPC8, and RPA9.

BINGO: RPB5, RPB11 and RPB8 are all 5V tolerant so UART2 will be our choice.

Now we look at TABLE 11-2 Right hand column and find U2TX.

The Pins available are: RPA3, RPB14, RPB0, RPB10, RPB9, RPC9, RPC2 and RPC4.

Just in case the cable is connected in reverse we should probably make our TX Pin 5V tolerant too, so we can narrow the selection to: RPB10 and RPB9.

Select a pair, any pair.
Well not quite.
We also have to consider any other Peripherals we may need to use, especially the Analogue ones as Analogue Peripherals can not be remapped by PPS, they have dedicated I/O.

Once you have weeded out the pins that are unavailable due to conflicts, the final decision can be determined by PCB routing. If you can simplify the routing or save a layer on the board by choosing a different Pin that is an added bonus.

In this case I will just select RPB10 and RPB11 as they are adjacent.

The Paperwork is almost done, but remember the 4 groups of pins? they are relevant.

We have selected to use U2RX on RPB11 and that was in the 2nd Section of TABLE 11-1 and U2TX on RPB10 in the 4th section of TABLE 11-2.

lets get back to creating code, and Plib again comes to the rescue, it avoids us having to directly set bits in registers by providing functions to do it for us.

PPSInput() and PPSOutput()

The arguments are in the order we read them from the tables so to set U2TX we say:

PPSOutput(4, RPB10, U2TX);

And to to set U2RX we say:

PPSInput (2, U2RX, RPB11);

Being able to assign pins like this in Software, whilst powerful, is also potentially dangerous.

If your program crashes or you mess up some pointer arithmetic in C you could start writing random data all over the memory map. If that happens there is the possibility of it inadvertently changing a pin allocation and blowing up external hardware or the CPU. In order to prevent that, PPS has a locking mechanism that requires certain values to be written in a certain sequence before the registers can be changed.

Fortunately Plib handles that for us too.

So we now say:

   PPSUnLock;

      PPSOutput(4, RPB10, U2TX);        // MAP Tx to PB10
      PPSInput (2, U2RX, RPB11);       // MAP Rx to PB11

   PPSLock;

the indentation is irrelevant, I just use it to show the blocking.

There is one more thing to consider.
The PPS functions set up the mapping but they do not setup the actual port.
That has to be done separately and with the usual consideration for turning off any Analogue functions.

mSETPORTBDigitalOut(RPB10);

and

mSETPORTBDigitalIn(RPB11);

takes care of that for us.

I need my bed so that is it for today, tomorrow we will look at actually using the UART.

Thanks for following along.

Cheers
Chris
« Last Edit: May 20, 2012, 07:52:49 PM by caroper »
 

Offline bxs

  • Regular Contributor
  • *
  • Posts: 89
  • Country: 00
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #15 on: May 22, 2012, 12:54:41 AM »
Great work, just keep it coming.

I also like this new SDIP PIC32, they are nice to play, I prefer the USB ones, like PIC32MX250F128B, even if the USB is not used it's nice for example for a USB bootloader so no USB-RS232 stuff.

As you said it's great for hobbyists, but I think that for simple things they are simple too expensive, better go with PIC 8bit or 16bit.

For 32bits final products NXP for example, have really cheap stuff, for quantities is goes a bit less than $1, once again, microchip don't have nothing not even near that, they probably don't want to kill the other PICs, but they end up killing PIC32 for entry level.

But for hobbyists, the price don't really matter and this new PIC32 are really nice to play, I love them  ;)
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #16 on: May 22, 2012, 08:38:00 PM »
Thanks,


Sorry for the delay in posting the UART Code, I got distracted prototyping other parts of the Project and ended up spending more time playing than I expected. Then work got in the way.
Customers are a pain but they do put bread on the table and the cash to buy bits to experiment with.


Update coming ASAP.


Cheers
Chris




Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1474
  • Country: pl
  • Troll Cave Electronics!
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #17 on: May 24, 2012, 07:58:02 AM »
Heh, the PPS is one of the main reasons for which I love dspic33/pic24h (I've got some samples of 'E' versions of both, but haven't tried those yet). It makes board layout SO much simpler.. :)
I love the smell of FR4 in the morning!
 

Offline xquercus

  • Contributor
  • Posts: 47
  • Country: us
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #18 on: May 24, 2012, 04:57:40 PM »
Nice tutorials.  Thanks for bringing my attention to this line.  I've really just ignored the 32-bit PICs but will have to get my feet wet at some point.
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #19 on: May 24, 2012, 07:06:54 PM »
PIC32MX Quickstart

Part 5 - The UART


We are moving away from hardware into software for this post so I will begin with the code and then explain it.

Attach the board to the PC via an FTDI connector or the PICKit2 UART Tool if you have a PICKit2 (I will talk about  using the UART Tool along with an expanded Schematic and Breadboard layout in another Post).

Set your terminal emulation to 38400 Baud, 8 Bit, No Parity, 1 Stop Bit.

Compile it and program the Chip, You should see 'Hello World!" appear on the Terminal each time you press  the reset button.


Code: [Select]

// Example 3.0


#pragma config   FNOSC       = FRCPLL
#pragma config   FPLLIDIV    = DIV_2
#pragma config   FPLLMUL    = MUL_20
#pragma config   FPLLODIV    = DIV_2
#pragma config   FPBDIV       = DIV_1


#define GetSystemClock()       (40000000ul)
#define GetPeripheralClock()    (GetSystemClock())


#define BaudRate   38400   // Maximim Rate of PICKit2 UART Tool


char Message[] = "Hello World!";


#include <plib.h>


void Serial_print(char *buffer)
{
   while(*buffer != (char)0)
   {
      while(!UARTTransmitterIsReady(UART2));
      UARTSendDataByte(UART2, *buffer++);
   }
    while(!UARTTransmissionHasCompleted(UART2));
   UARTSendDataByte(UART2, '\r');
   UARTSendDataByte(UART2, '\n');
}


main()
{
   SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

    mPORTAClearBits(BIT_0);                 //Clear bits to ensure the LED is off.
    mPORTASetBits  (BIT_1);                 //Clear bits to ensure the LED is off.
    mPORTASetPinsDigitalOut(BIT_0|BIT_1);   //Set port as output

   mPORTBClearBits(BIT_10);   
   mPORTBSetPinsDigitalOut(BIT_10);      // Set PB10(Tx) as output
   mPORTBSetPinsDigitalIn (BIT_11);      // Set PB11(Rx) as input

   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));   

   Serial_print(Message);

   int j;

    while(1)   
    {
        j = 100000;
        mPORTAToggleBits(BIT_0|BIT_1);      //Toggle light status.
        while(j--);                       //Kill time.
    }
}

Like most things in the PIC32 the UART has been considerably enhanced over the UART in the 8Bit PIC's.  Once again PLib is used to abstract out the complexity of addressing individual registers and bits.

Lets have a look at the code additions in order of execution.

UART Configuration.

UARTConfigure(UART2, UART_ENABLE_PINS_TX_RX_ONLY); 

The PIC32 can have up to six UART's, however, UART's can now be paired up to automatically handle Hardware Handshaking. Effectively that means you can have 6 simple UART's, 3 UART's with Hardware Handshaking or any combination in between. The Constant 'UART_ENABLE_PINS_TX_RX_ONLY' is telling PLib that we only want basic UART functionality, that is No Handshaking.

The next line is the same as the parameters that we set in the Terminal emulation.

UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1); 

The PIC32 derives it's UART Timing from the peripheral bus, that is the reason we have:

#define GetPeripheralClock()    (GetSystemClock()) .

PLib uses it in this case to determine the register values for our chosen BaudRate. If we change either the System Clock or the Peripheral Clock we only have to alter the code in one place and it will be able to recalculate everything for us.

I place the line: 

#define BaudRate   38400

at the top of the code so that it can be easily changed whilst experimenting and to keep it grouped with the rest of the system timing  parameters.

Finally we enable the UART.


UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));   

 Interfacing with the UART

Serial_print(Message) is a function call. Lets break down the Function.

Code: [Select]
void Serial_print(char *buffer)
{
   while(*buffer != (char)0)
   {
      while(!UARTTransmitterIsReady(UART2));
      UARTSendDataByte(UART2, *buffer++);
   }
    while(!UARTTransmissionHasCompleted(UART2));
   UARTSendDataByte(UART2, '\r');
   UARTSendDataByte(UART2, '\n');
}

I am a hardware not a Software guy, and I am also new to C.  I started learning C specificaly to use the PIC32, so I will not presume to teach you C Programming. I will, however, point out what PLIb is doing for us again.

char *buffer is a pointer to a string, the string in question is the one we defined at the start of the code with the line:

char Message[] = "Hello World!";

and passed into the Function with the line:

Serial_print(Message);

Our Function will step through that string sending one character at a time followed by CR-LF.

The PIC32 UART's include both a TX and an RX Buffer in hardware, it is not large, only 4 bytes each, but it can be useful and makes using the UART's easier in a lot of cases.

The function  UARTTransmitterIsReady(UART2) will be TRUE if one or more Bytes of the Tx buffer are empty and ready to receive data. So the line:

while(!UARTTransmitterIsReady(UART2)); 

is effectively waiting for buffer space before sending the next Character with the line:

UARTSendDataByte(UART2, *buffer++);


UARTTransmissionHasCompleted(UART2) returns TRUE is the Tx Buffer is empty.
We are using it in the loop:

while(!UARTTransmissionHasCompleted(UART2));

to wait until our Message has been sent.

The CR and LF characters are sent without any poling as we know the 4 Byte Tx Buffer is empty, so in this case we can fire and forget.

Well that's it for this post but I should point out where you can got more information on PLib.

In MPLab select Help -> Topics...
and under Language Tools you should see: C32 Peripheral Lib Guide.

And a well hidden PDF document exists (as of this posting) on the Microchip web site:  http://ww1.microchip.com/downloads/en/DeviceDoc/32bitPeripheralLibraryGuide.pdf
 
Cheers
Chris

« Last Edit: May 24, 2012, 08:54:28 PM by caroper »
 

Offline LuckyJaker

  • Contributor
  • Posts: 16
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #20 on: May 25, 2012, 11:59:55 PM »
I wish I read your articles before I started programming the PIC32...
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #21 on: May 26, 2012, 06:28:32 AM »

PIC32MX Quickstart


Part 6 - an Extra Timer and Interrupts

The PIC32MX has a nice complement of timers, five by 16 bit which may be paired to form one 16 bit and two 32 bit timers or any combination. These timers are similar to the ones we know from the rest of the PIC line, and I will go into more detail on them in a later post. I mention them here because what is often overlooked, and indeed not even mentioned in the Data Sheets as far as I can tell, is the existence of a yet another 32 Bit Timer.

We already know that the PIC32MX family of Microcontrollers are based on the MIPS M4K Core, well it just so happens that the MIPS M4K Core contains a 32 bit Timer.

This timer is like gold, just about every program ever written for a Microcontroller needs a timing source, usually of 1mS, and to achieve that one of the valuable Timer/Counter modules is often sacrificed.

Lets then have a look at how we can use the Core Timer to provide us with that  useful function effectively for free.

The MIPS Core Timer

The Core Timer is a 32 Bit Timer that is fed from the System Clock, as opposed to the peripheral clock,  via a divide by 2 input. We have no control over the prescaler and it starts Timing as soon as the Oscillator starts running. If we are running our Clock at 40Mhz then the Tick rate of the Core Timer is going to be 50ns and the depth of 32 bits means it will count for 220 Seconds before it rolls over.

Whilst we cannot start or stop the timer, we can clear it or reload it. More importantly, it can generate an interrupt.

Lets have a look at some code to do just that.

First we decide how often we want the interrupt to occur, in this case we want a 1mS Tick, we have already defined GetSystemClock() and we know that it is divided by 2 before being fed to the Core Timer, so if we divide that by 1000 we have the CORE_TICK_RATE, that is required for an interrupt every 1mS.

#define CORE_TICK_RATE (GetSystemClock() / 2 / 1000)

We now have to pass that value to the Core Timer itself and as usual PLib has a function for that:

OpenCoreTimer(CORE_TICK_RATE);

That Function is going to Set a Flag bit and optionally fire an interrupt when the Value in CORE_TICK_RATE is reached. Let’s use the latter option:

mConfigIntCoreTimer((CT_INT_ON | CT_INT_PRIOR_2 | CT_INT_SUB_PRIOR_0));

This macro Enables the Core Timer Interrupt, assigns it a Priority of 2 and a Sub Priority of zero.
You will have noticed 2 important things here:

1) The PIC32 has interrupt Priority levels.
2) Interrupts can be prioritised within an interrupt priority level.

This is referred to as MultiVectored interrupts.

What is particularly powerful in the PIC32 architecture is that the Interrupt Controller is separated from the CPU. That means that Interrupts are prioritised before being presented to the CPU, it also allows such things as edge polarity control and Software generated Interrupts. In fact the documentation on the Interrupt controller is longer than the Documentation of many of the PIC10F series devices. But we don’t need to concern ourselves with most of it, because PLib is hiding all the complexity anyway.

What we do need to know is that each interrupt can have one of seven priority levels, where 1 is the lowest priority and 7 is the highest priority, and within each priority Level there are four sub priority levels where 0 is the lowest priority and 3 is the highest priority. Notice that the main priority level counts from 1, a priority level of zero is equivalent to disabling the interrupt. It is also useful to know that the priority 7 interrupts use a shadow register set to save the time normally required to Push and Pull the working registers in an interrupt service routine.

In order to actually use  the interrupts we need to turn them on first and Just to prove that Microchip Engineers do have a sense of humour I quote this from some correspondence with them:
Quote
Remember to match the assigned level with the _ISR() declaration.  Replace the initialization function call with the new multivectored version:

INTEnableSystemMultiVectoredInt(); .

Send me an email if you managed to type the preceding function call without any typo on your first try. Courtesy of the PIC32 libraries ’team, you could be the winner of a yet-to-be-determined grand prize for the “longestfunctioncallspelledwithouterrorsatfirsttry” contest!:
 

Which pretty much sums up the whole of PLib as I am sure you have noticed by now.

Handling Interrupts

When an interrupt is generated it is prioritised by the Interrupt controller and then passed to the CPU as an interrupt vector. In order to process that interrupt we need to generate code associated with the appropriate Interrupt vector.

As there are up to 96 interrupt sources distributed amongst 64 interrupt vectors we are very fortunate that they have been defined for us in advance in the PLib Header files. All we need to know is that we are using:

_CORE_TIMER_VECTOR

Note the proceeding underscore.

and to create the interrupt handler we use the special function statement:

__ISR()

This time notice the two underscores. This syntax is critical to the compiler.

An interrupt handler has no return value so it is declared as void and we need to pass it the Vector it is handling, the priority level and a function name (used by the linker and debugger)

void __ISR(_CORE_TIMER_VECTOR, ipl2) CoreTimerHandler(void)

You should never do much inside an Interrupt handler, keep it as short as possible.
In this case we need to increment our milliseconds count and initialise our Core Timer and critically, clear the interrupt flag to prevent it from immediately triggering on exit.

Our milliseconds count we will keep in a global variable and as it is going to be changed inside an interrupt service routine, outside of the compilers control, we need to define it as volatile, this warns the compiler not to try and optimize it in any way.

volatile unsigned long  gmscount;

The code looks like this:

gmscount++;
UpdateCoreTimer(CORE_TICK_RATE);
mCTClearIntFlag();

Finally we need some code to test that it is working so let’s define a delay function to replace the loop we are currently using to flash the LED.

void delay(unsigned long msdelay)
{
   unsigned long startTime = gmscount;
   while(gmscount - startTime < msdelay);
}

our body code will then change to:

PORTToggleBits(IOPORT_A, BIT_0);
delay(500);

which should flash the LED every second.
   
Lets put it all together and try it out:

Code: [Select]
// Example 4.0


#pragma config   FNOSC       = FRCPLL
#pragma config   FPLLIDIV    = DIV_2
#pragma config   FPLLMUL    = MUL_20
#pragma config   FPLLODIV    = DIV_2
#pragma config   FPBDIV       = DIV_1


#define GetSystemClock()       (40000000ul)
#define GetPeripheralClock()    (GetSystemClock())
#define CORE_TICK_RATE (GetSystemClock() / 2 / 1000) // 1mS
#define BaudRate   38400   // Maximim Rate of PICKit2 UART Tool


#include <plib.h>


char Message[] = "Hello World!";
volatile unsigned long gmscount;;


void delay(unsigned long msdelay)
{
   unsigned long startTime = gmscount;
   while(gmscount - startTime < msdelay);
}


void Serial_print(char *buffer)
{
   while(*buffer != (char)0)
   {
      while(!UARTTransmitterIsReady(UART2));
      UARTSendDataByte(UART2, *buffer++);
   }
    while(!UARTTransmissionHasCompleted(UART2));
   UARTSendDataByte(UART2, '\r');
   UARTSendDataByte(UART2, '\n');
}


main()
{
   SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);


    OpenCoreTimer(CORE_TICK_RATE);
    mConfigIntCoreTimer((CT_INT_ON | CT_INT_PRIOR_2 | CT_INT_SUB_PRIOR_0));


    INTEnableSystemMultiVectoredInt();


    mPORTAClearBits(BIT_0);                 //Clear bits to ensure the LED is off.
    mPORTASetBits  (BIT_1);                 //Clear bits to ensure the LED is off.
    mPORTASetPinsDigitalOut(BIT_0|BIT_1);   //Set port as output


   mPORTBClearBits(BIT_10);   
   mPORTBSetPinsDigitalOut(BIT_10);      // Set PB10(Tx) as output
   mPORTBSetPinsDigitalIn (BIT_11);      // Set PB11(Rx) as input


   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));   


   Serial_print(Message);


   int j;


    while(1)   
    {
      PORTToggleBits(IOPORT_A, BIT_0);
      delay(500);
   }
}


// Interupt Handlers


void __ISR(_CORE_TIMER_VECTOR, ipl2) CoreTimerHandler(void)
{
   gmscount++;
    UpdateCoreTimer(CORE_TICK_RATE);
    mCTClearIntFlag();
}

Compile it and program the chip.

you should now have an LED that flashes at exactly 1 second and a frequancy of 1Hz if you still have a frequency counter attached. in my case the frequency counter reads 1.002Hz, which when you consider we are using an RC oscillator is pretty remarkable accuracy.


There is a register that we can use to calibrate the internal RC oscillator, if we wanted greater accuracy, but it is stable enough for fairly high speed serial communications as it is and if we need more accuracy for time functions we have a Built in RTCC. That will be discussed soon.


That’s it for today,

Till next time,

Cheers
Chris
« Last Edit: May 26, 2012, 07:41:18 AM by caroper »
 

Offline caroper

  • Regular Contributor
  • *
  • Posts: 193
  • Country: za
    • Take your PIC
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #22 on: June 07, 2012, 08:22:02 AM »
For those of you that are interested in trying the PIC32 but have been put off by only having a PICKit2 programmer here is a great deal.

You can get the Microstick II with integrated Programmer/Debugger and an assortment of CPU's for $3.49 if you enter the code "MCHPPIC32".

Thanks to mukymuk for the heads up on this one.

I have ordered one, they only have 4 left as of my order, but are getting new stock on the 18th, so future installments of this thread will include examples with the PIC32MX250F128.

Cheers
Chris


Offline baljemmett

  • Supporter
  • ****
  • Posts: 666
  • Country: gb
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #23 on: June 07, 2012, 11:42:59 PM »
For those of you that are interested in trying the PIC32 but have been put off by only having a PICKit2 programmer here is a great deal.

Indeed, and for those of us still using a PICkit 1 (with a flying DIP8-to-ICSP lead, I'm not a total masochist) it was a no-brainer.  Many thanks to mukymuk for the tip!  Chucked in a few jellybean PICs to replenish my depleted stocks, though, just so the shipping wasn't more than twice as much as the goods total ;)
 

Offline BloodyCactus

  • Frequent Contributor
  • **
  • Posts: 439
  • Country: us
Re: PIC32MX Quickstart - A Tutorial for Hobbyists
« Reply #24 on: June 10, 2012, 02:00:15 PM »
shoot. good a reason as any to grab one and a couple of extra chips for experimenting
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf