My previous post went over the various components of the MPLAB IDE and UBW32 bootloader. Now I’ll show you how to use those software tools to upload a simple sample project while discussing the basics of PIC32 programming. Read on for the rest of the UBW32 getting started post complete with a very basic PIC32 programming overview.
At this point you should have the MPLAB software installed and running as per the guides in part 1 of this post. The next step is to open up a project file. This project file consists of a number of files that are all compiled together to make your final program. I am providing a zip file of the project file and support files I will be using in this example. I have modified the Hello World project files from the UBW32 website so that they will be a bit more familiar to people used to using the Arduino IDE. I have also added a number of comments to try and explain what everything in the files is doing. I will now discuss these files to give a brief overview of the basics of C32 programming.
To open my project file, you need to extract the zip above and open the HelloWorld.mcp file. This .mcp file contains links to all the files needed to compile your project. It shows them on the left side of the screen, as seen in this picture:
You’ll note that there are several files listed here. The first is main.c, which initializes the UBW32 board to run, and sets up the setup() and loop() functions that should be familiar to all Arduino users. I am including it here with all my comments on what each part of the program is doing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /******************************************************************** Super simple HelloWorld (blink some LEDs) for use with UBW32 hardware see http:/*www.schmalzhaus.com/UBW32 for more info Modified by Tim of http:/*BeyondArduino.com to include more comments and explainations. ********************************************************************/ /* 11/13/2011 - updated by Tim to add comments and better explain the inner workings of the UBW32 /* 06/01/2010 - updated to use latest MPLAB and C32 compiler */ /* 08/28/2010 - Changed to use Microchip folder - from Microchip Applications Library USB stack v2.7 - updated project to use unchanged MAL Microchip folder - no code changes */ /* 09/02/2011 - Tested with USB stack v2.9a, C32 v2.01, MPLAB v8.76 - no code changes */ /*The plib.h library includes the #defines and functions needed to access most all of the PIC32's built in features. You will want to #include this in all your PIC32 projects to make using the PIC a pleasant experience. This library contains the equivalent of the Arduino built-in Functions, such as digitalWrite() and pinMode(), and everything up to controlling your serial pins, USB and all other chip features. It is practically essential for PIC32 programming using the MPLAB C32 Compiler.*/ #include <plib.h> /*this is a file made by the UBW32 team that specifies pin definitions and states for the UBW32 board specifically, including the user-controlled switches and the LEDs. You'll want to include this whenever you're working with the UBW32 board. It includes commands to check switch states, init all the LEDs, and to set LED states or toggle them. Very handy for simple UBW32 board controls.*/ #include "HardwareProfile.h" /* NOTE THAT BECAUSE WE USE THE BOOTLOADER, NO CONFIGURATION IS NECESSARY*/ /* THE BOOTLOADER PROJECT ACTUALLY CONTROLS ALL OF OUR CONFIG BITS*/ /* Let compile time pre-processor calculate the CORE_TICK_PERIOD*/ #define SYS_FREQ (80000000L) /*this sets the system frequency to 80Mhz*/ #define TOGGLES_PER_SEC 1000 /*This is the number of divisions per second you want the timer to tick at.*/ #define CORE_TICK_RATE (SYS_FREQ/2/TOGGLES_PER_SEC) /*this sets the CORE_TICK_RATE, which will control how often a timer-based interrupt occurs based on your TOGGLES_PER_SEC value*/ /* Decriments every 1 ms.*/ volatile static uint32 one_ms_timer; /*this is the helper file that contains the user-configured setup() and loop() files, and where most of your code should be written. Note that any variables defined before this #include will be accessible to you as global variables in your functions, and that any defined after will not, and trying to use them in setup() and loop() will result in compile errors.*/ #include "program_functions.h" /*after being reset, the PIC will run this main() function one time and then do nothing. It begins by initializing the system variables and then calling a setup() function (Just like the Arduino). After the setup function runs, the main() function enabled multi-vector interrupts, and then runs a loop() function continuously until the PIC is reset or loses power.*/ int main(void) { /* Configure the proper PB frequency and the number of wait states*/ SYSTEMConfigPerformance(80000000L); /* Turn off JTAG so we get the pins back: JTAG is a debugging system that the PIC32 supports, but we don't need to use it.*/ mJTAGPortEnable(0); /* Open up the core timer at our CORE_TICK_RATE as defined above*/ OpenCoreTimer(CORE_TICK_RATE); /* set up the core timer interrupt with a prioirty of 2 and zero sub-priority*/ mConfigIntCoreTimer((CT_INT_ON | CT_INT_PRIOR_2 | CT_INT_SUB_PRIOR_0)); /* Set all analog pins to be digital I/O The PIC defaults the analog pins to being analog pins when initially configured. Since in most cases, you'll be using them for digital I/O instead, this line is included when the chip initializes to allow for the use of the analog pins as digital I/O pins. If you want to set them up as Analog input pins, you'll need to change the configuration in setup();*/ AD1PCFG = 0xFFFF; /*setup() works just like the setup() function on an arduino board. it will run once at reset, then never again.*/ setup(); /* enable multi-vector interrupts These allow interrupt messages to the PIC to list what type of interrupt they are to make handling them much faster. Look ot future blog posts from beyondarduino.com to explain the interrupt system in greater depth.*/ INTEnableSystemMultiVectoredInt(); while(1) { /*the loop function now runs your custom code just like in an arduino. It will run continuously until the PIC is reset.*/ loop(); } } /*this is the function that runs every CORE_TICK_RATE for controlling a timer. It is an interrupt function, so it will stop executing code in your loop() function and run this function immediately. It should be noted that interrupts should be kept as short as possible to avoid bogging your program down.*/ void __ISR(_CORE_TIMER_VECTOR, ipl2) CoreTimerHandler(void) { /* clear the interrupt flag /*clearing this flag allows the normal code to resume after this interrupt function has run, and allows the interrupt to be called again*/ mCTClearIntFlag(); /*the way the timer is setup is similar to the arduino example "blink without delay". In "Blink Without Delay" the number of miliseconds is counted from when the arduino starts, and the value is compared to the last time the LED changed states. In this code, a 'countdown timer' (one_ms_timer) is assigned in your loop() function which tells the program to count down every CORE_TICK_RATE until the timer value is 0. So in the loop() function, it will check to see if the timer has run out, and if it has, it will reset the timer to start over after preforming an action. This is basically backwards from the arduino, but it should be fairly simple once you get the hang of it.*/ if (one_ms_timer) { one_ms_timer--; } /*this tells the core timer how many ticks to wait before triggering the interrupt again. If you do not set this, the core timer will not continue to be triggered.*/ UpdateCoreTimer(CORE_TICK_RATE); } |
I hope that my comments have made the code easier to follow for those who are interested. The next function is the “HardwareProfile.h” provided by the UBW32 devs. I have not altered this file, but it allows you to use the UBW32 hardware easily through #defined function calls. I’ll let you look through it in the zip file on your own. The third file is the “program_functions.h” file, included below. This file contains the setup() and loop() functions you’ve come to expect from an Arduino, and should be pretty easy to understand coming from the Arduino IDE.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /* Program_functions.h by Tim Anderson as part of a UBW32 Hello World Project This should look roughly like an Arduino IDE function now. The PIC will call setup() once upon reset and then call loop() forever more. */ /*Once you get used to using the PIC, you'll probably not need to modify the main.c file very much. All your program code can be handled in the setup() and loop() functions just like with the Arduino. The only difference is you get to peek at some of what's happening in the background and have the ability to easily modify it while using the UBW32.*/ /*as with the Arduino, setup() is called once and runs only after a reset.*/ void setup(){ /*Initialize all of the LED pins on the UBW32. This is one of the built-in functions of HardwareProfile.h It configures all 4 of the user-controlled LED pins to be outputs, and sets them all to the LOW state, turning them off.*/ mInitAllLEDs(); /*This is another HardwareProfile.h function that will set LED2 ( The white LED) to be on when the system is first initialized.*/ mLED_2_On(); /*this will initialize the one_ms_timer to trigger after 1000ms, or 1 second, has passed.*/ one_ms_timer = 1000; } /*this loop function will be called continuously for as long as the PIC is running. it works just like the loop() function on the Arduino.*/ void loop(){ /*Since our goal is simply to blink an LED, all we'll be doing is checking to see if our countdown timer has run out, then toggling the LED and resetting it.*/ if(!one_ms_timer){ mLED_2_Toggle();/*this is a HardwareProfiles.h function for changing the state of an LED on the UBW32.*/ one_ms_timer = 1000; /*this resets the timer so that the LED will toggle again in one second.*/ } } |
The final file is very important. It is called “procdefs.ld” and is listed under the ‘other files’ heading. This file needs to be included in your build so that the compiler knows what memory addresses the bootloader is occupying and not to write to them. If you forget to include this file, it is possible you will overwrite your bootloader and be left with a broken UBW32. You won’t need to modify it at all, but make sure you have it included in your builds.
Now that you know what goes into the files, you just need to build them and upload the .hex file they produce to your UBW32. To do this click the ‘Build All’ button (it looks like a stack of paper with two arrows pointing down on it) and let MPLAB compile everything. If it all went well, you should see something like this:

If you run into problems with missing references, make sure you have the Microchip Application Libraries properly installed and that MPLAB knows where they are. Once your project has built successfully, you will notice several new files have been generated in your HelloWorld folder. The important one is the HelloWorld.hex file. For the next step you need to get your UBW32 into bootloader mode. To do this, hold down the “PROG” button and press the reset button. It should turn on the yellow and red LEDs and alternate blinking white and green LEDs. That means it is ready to receive your new project code.
Now you need to open the HIDBootloader.exe file you downloaded. It will open a small window, and should say ‘Device Attached.’ If your UBW32 is in bootloader mode and plugged into the USB port. If it doesn’t recognize it, you may need to install driver software from the UBW32 site. Next, you need to select your newly generated .hex file by clicking the ‘Open Hex File’ button and navigating to the hex file. Finally, you just need to click on the ‘Program/Verify’ button and it will erase, program and verify your new code as shown below.



Then you can click ‘Reset Device’ or press the reset button on the UBW32 board and you should have a blinking white LED. With that you’re good to start experimenting with your own code and get programming. In next week’s blog post, I’ll go over the register system used by the UBW32 and show you how to control I/O on all the board’s pins, not just the LEDs and Switches provided on the UBW32 board.

Comments are closed.