Prabir Roy, Software Engineer
Black Oak Engineering
New York USA
Here is a simple introduction to the Microchip Code Configurator (MCC). In this first blog post I am using Melody for a PIC18F16Q41, but later posts will include Harmony for PIC32. The workflows are quite similar, though obviously we will be adding much more complicated functionality as we progress. We will always be building into a real target; these are not mere academic exercises. We will solve the inevitable problems as we go.
Figure 1 shows a section from the schematic that we will use. I got this from the hardware team. They assure me that it will work. Let’s just see.
The micro, again, is the PIC18F16Q41T in an SOIC-20 package. Pretty simple chip. For the project we need a UART and SPI, no ADCs, an internal clock. Not much else. We need the micro to run the Black Oak Engineering Acorn API, which is compact, but does have strict timing requirements.

Some preliminary general notes.
• Microchip dev tools are growing rapidly. It is hard to keep up with all of the changes. But
this is a good problem to have. Better to grab a tiger’s tail than a boring old dead stick.
Questions and answers on forums, reference wikis, videos, and app notes abound online.
But those from even a few years ago are already out of date. If it pertains to ϐirmware, the
shelf life is less than four years. Microchip’s own tutorials tend to lag the pace of the
development ecosystem growth.
• MCC is a code configurator that is embedded in the MPLAB IDE. Like those of other
manufacturers, it is a graphic way to depict and setup the chip and its function blocks.
Melody (PIC18 & dsPIC) and Harmony (PIC32) are frameworks that are also generated by
MCC. They provide a consistent, orderly method for initially structuring your projects.
This is not an operating system, but it is a good foundation for an OS. We have
implemented FreeRTOS this way.
• Microchip MPLAB supports MISRA and thread safety checking.
• Combinations. No automobile has a button that says: ‘Drive off a cliff’. Micros do have
such controls, however. Many of them. They’re not called ‘Drive off a cliff’, of course, but
their lethality is the same. For example, it is easy to configure a clock to run so fast that,
instead of the 480 MHz that you thought you were asking for, you get an alias of 12 MHz.
And you do not know this happened unless you independently verify. MCC helps to
mitigate this problem, but it’s still easy to drive off a cliff.
• In embedded programming, setting one single bit incorrectly can easily cause a function to
not work at all, and it may not be obvious what went wrong. In general the default values
are good starting points. Use them unless you are certain of how they should be differently
assigned. And changing one bit may easily affect the actions of a dozen others.
• Generality. Micros are designed to support multiple functions and multiple customers.
Sometimes too much so. One doubts that some esoteric possibilities are ever actually used
by anyone, or that they have been fully tested in action. You may not, for example, be able
to have both CAN communications and two EUARTs in one chip. Or QSPI is available but
requires an elaborate DMA scheme that must be co-developed. With a given project and
its selected micro, you typically have exactly one way only that you want to use a given
function. The micro manufacturer gives you several. So you need to specialize down on
your needs.
• It’s a trade-off. If the micro is commercially available, not overpriced, (and not
underpriced due to an unsustainable subsidy), meets its basic specs, and meets your
needed basic functionality, this is enough. And if Microchip is pushing the edge of
functionality and integration in some areas, be glad for the basic functionality, which is
quite reliable. We have found that Microchip meets these basic criteria better than many
others.
• To be honest, we used to eschew MCC Harmony and Melody at Black Oak Engineering. We
were truly ‘bare metal’ programmers. We did the initial setup by hand, and usually arrived
at the same code. Our code was leaner, but we frequently ran into intractable problems.
The myriad of options is confusing, especially as more demanding functionality is brought
in. This complexity is only getting worse. The newer IDE tools really do help to conϐigure,
debug, and modify a project. Documentation tools and version control are built in.
• One big advantage of MCC Melody and Harmony is that there is high uniϐication between
the Atmel-derived parts, including the ARM-based ones, and the original Microchip
architectures.
Workflow
1. Preparation
a) Attach the programming tool. Here I will use an ICD4.
b) Start MPLAB X IDE. I am using v6.20.
c) Start a New project.
d) Select your PIC. Here we are using a PIC18F16Q41.
e) Select your programming tool.
f) Select your compiler version. Here I am using XC8 ver 2.5. As a general rule, we try to stay current with software tools. Fixing minor glitches every few weeks is better than trying to fix major breakdowns every year or so. Of course, sometimes major version updates should wait. For instance, if ver 3.00 just came out, wait for ver 3.01 unless you like to live dangerously.
g) Name the project.
h) Start MCC (the icon button) if it has not automatically started. Some content may need to download pertaining to your project. This is fairly quick and the files are seldom inordinately large, as happens with, say, Zephyr.
Note, we need to assign basic functionality before we assign pins because this will enable the desired options for the pins. By default they are simply general purpose IO pins. For example, if we do not have EUART1 assigned, we will not get the option to assign the Tx line to a given pin that supports EUART1 Tx.
2. Clocks
a) In this example we have only the internal clock.
b) Select Clock Control either in Project Resources on the left, or the graphic button in the center. Either will yield a Clock Control tab in the Toolbar window on the right.
c) Set Generate Initializer Code to Initialize all registers.
d) Set Clock Source. Here we use 64_MHz, Clock Divider = 1. As always, faster clocking means more current consumption, but that is okay for this project. It also gives us more latitude in setting up serial communications and other temporal processes.
e) The read-only System Clock is shown.
f) Leave the Secondary Oscillator off. This is typically used for a 32.768 kHz real time clock crystal, which this project lacks.
g) The important internal clock Fosc runs at ¼ the frequency of the primary clock.
h) If we enable CLKOUT and set it to express Fosc, we expect to see, in this example, 16 MHz on PORTA.4. We see this verified in Figure 2.

3. Configuration bits
These are basic controls that determine the micro’s clocking mechanisms, Watchdog Timer, ICSP, security, and many other systems. In general, these cannot be modified at runtime.
If in doubt, turn it off to start. You can usually get a project started, and then experimentally add a possibly disruptive feature as you go.
In the Toolbar window you can open a tab which shows the Registers and their resultant values. Later, when we Generate the initial source code, these will all be incorporated into initialization code. In other words, you do not need to manually copy these values into the project source, as one did before MCC.
I show here only some of the specific changes that I made for this project. Otherwise I left the defaults alone.
a) CONFIG1
Here we say Oscillator not enabled. The dropdown shows 'HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1'.
b) CONFIG2
For simplicity, disable Fail-Safe Clock Monitor.
Clock Out is very useful if you have a spare pin to use it with. In our case we do, PORTA.4 may be used as CLKOUT. The Pin Grid View tells us this.
There are many more Configuration bits, even for a simple PIC18F micro. They are all fairly important, but I concentrate only on the basic, initially important ones here.
4. Driver Resources
Here is where we add the function blocks that our project requires. Here we hopefully confirm that the micro we selected is up to the task. See Figure 3.
a) Navigate over to Add Generic Driver Interfaces. Here we are going to add SPI and UART.
b) In Driver Resources, open SPI. Click the green-plus for SPI1.
c) Do the same for UART. You will need to select a 'dependency' in the right-side Toolbar window. Here we use UART1.

d) Notice that the Pin Grid View has now added specific functionality to the pins. We must match this with our schematic. By the way, this is a good time to review the schematic. The designer may have made mistakes that are best corrected right now.
e) Our PIC18F16Q41 supports two SPI channels. We choose SPI1. Host mode.
f) In other words, our micro will be the ‘M’ in 'MOSI' (‘Micro Out - Serial Device In’). We will generate the synchronous SPI clock. In another project we may want our micro to be the device that is passively driven by an external Host.
g) Mode 0 is the most common. This tells the micro to sample MISO data on the rising clock edge.
h) Here we have a SPI clock frequency of 1 MHz, which is rarely a problem to support for peripheral devices.
i) We will not use interrupts for now. We will simply poll.
j) Our clock source is the Fosc, suitably scaled down.
What about the UART?
a) The default is 9600 baud, but it is convenient to run a little faster. So enter ‘115200’ here. The actual clock rate is slightly off, with a Baud Error Rate of 0.08%. This low error is not a problem. b) No parity, 8 data bits, 1 stop, is the most common setting, with no flow control. Again, no interrupts yet. We will add interrupts in a future post.
c) Be sure to set ‘Redirect printf to UART’. This is not done automatically; here is where we must formally associate printf().
d) Note, Microchip traditionally referred to the asynchronous transceiver as the ‘EUSART’, the ‘Extended Universal Synchronous and Asynchronous Receiver Transmitter’, because indeed we may use these ports for a wide variety of tasks. This is still the case, but Microchip is sometimes calling this simply the 'UART' now. We use UART1 for the PLIB.
e) PLIB refers to the Peripheral Libraries. These have evolved considerably from where they were years ago.
f) Figure 4 shows our MCC UART setup.

5. Pins
I like to name the pins so that they correspond to the schematic. You could stick with the generic names, but that leads to confusion. Why multiply names unnecessarily? The schematic designer may have no idea what you mean by 'IO_RB6'. She thinks of that as 'SCK1'.
a) Go CCW around the chip, naming and conϐiguring the pins. There is a graphic, clickable IC in lower left that you can use.
b) In the Pin Grid View, click on blue unlocked icons. Make sure you have the correct Package type in the dropdown. In this project I have an SOIC-20 package.
c) The Toolbar window pops up on the right side. Expand as necessary.
d) Remember, unassigned GPIOs should be output 0's.
e) Note, at BOE we usually break out unassigned IO with a small through-hole pad. They're named W1, etc. In the early stage of development these are often called into use.
f) The default is to initialize pins low. In some cases, as with SPI chip selects, you definitely want to init high. Our naming convention for assert-low pins is to append ‘_n’, as in ‘RTC_CS_n’.
g) Remember that, everything else being equal, GPIO pins often default to analog inputs, not to digital. MCC handles this automatically. If you assign them a digital task, the analog connection will be turned off.
h) You will get notifications as you go regarding possible pin problems. Needless to say, you want to fix these before you proceed much further.
i) If the pin is an output:
▪ Should it initialize high?
▪ Is it open drain? Open drain outputs are common. They require a pullup resistor. An open drain output may be tied to other open drain outputs as a type of ‘OR’ gate.
▪ Should the slew rate be limited? You often do want this to deliberately slow the rising and falling edges for a given frequency signal (which must obviously be a frequency lower than what the slew rate limitation allows). Slew rate limiting yields cleaner wave forms and less RF emissions.
j) If the pin is an input:
▪ Is there a weak pullup? This is a useful feature that many micros support. If the designer forgot to add an external resistor, or to save board space and cost, we can simply use a built-in pullup. Weak means that it is high impedance, so it can be easily overridden with an external, relatively low impedance.
▪ Do we want a Schmitt Trigger comparator to sharpen transitions when the signal is noisy and ‘non-digital’? This is generally preferred.
k) If you accidentally lock a pin into two different roles, just unlock the unwanted role.
Figure 5 depicts our pin setup with names I assigned.

6. Generate
Now we are ready to create code.
a) Click the Generate button in the Project Resources window. You will see a flurry of activity in Output at the bottom window. A whole, structured proto-project has been built for you.
b) Click the Build for Debugging (hammer icon) button. You should build without any errors at this stage. You will, however, have a slew of warnings about unused C functions. Indeed, the Melody and Harmony frameworks generate a vast toolbox of C functions at your disposal. You are free to delete the unused ones.
c) Click on the Projects tab in top left to see our nascent firmware project.
d) We try to stick with the logical structure and naming conventions that MCC yields. They are slightly verbose, but they are lucid, and standards are usually to be preferred. So why fight the IDE?
e) All of the files contain much ‘boilerplate’ content. This is important, but will not be shown here for the sake of simplicity.
f) There is built-in support for Doxygen commentation.
7. The Project
a) We add our own ‘business logic’ files under the Header Files and Source Files folders. Usually this will become the largest part of the project.
b) main.c holds the rudimentary SYSTEM_Initialize() followed by a while(1) exec loop.
c) As a first programming step, let’s get a simple printf() working to the UART. Note, as mentioned above, with MPLAB one must formally assign the use of printf() to one UART. The exact method depends on the chip.
d) Here we scroll down through Device Resources and add the UART Example. This will show up in the center tree diagram, and the setup parameters will appear as a tab in the right-side Toolbar.
e) Select ‘1. UART Printf with Variable Counter’. We will do this Polled for now.
f) In UART Conϐiguration, for our present purposes, I check all of the boxes.
g) To proceed, the instructions now are given in the window at bottom right:
▪ Click Generate.
▪ Navigate to the examples folder. This is under the MCC Generated Files folder.
▪ Copy and paste the code snippet within the dashed lines.
▪ Complete any TODO tasks in the generated code. Here there are none.
h) We do, however, want to start building our project correctly, and not just dump everything in main.c. So I make a new file under Source Files called serial.c. Then:
▪ Cut out the example code and paste it into the new file.
▪ Cut ‘(void) UART_PrintLoop(5);’ from the extra main() function. Paste it into the original main() function. The ‘(void)’ cast is redundant. Delete the extra main() function entirely.
▪ Make a new C Header File called ‘serial.h’ under Header Files.
▪ Cut out the ‘void UART_PrintLoop(int count);’ declaration. Copy that into serial.h. Note that inclusion guarding is automatically generated.
▪ Back in serial.c, add ‘#include "serial.h"’, which should be readily available on the dropdown list. (If it is not you have a pathing problem.) Do the same in main.c. Do this in any C file that needs the serial functionality.
Obviously, you are free to structure your code as you see fit. This is not the only possible path in the workflow.
i) Click hammer build. It builds, but I had a warning about ‘implicit declaration of function ‘printf’ is invalid in C99 ’. Something is wrong. We need to take these warnings seriously. In this case I know what the problem is. I need to add ’#include ’ atop serial.h, or wherever it will be seen when printf() is called. Recompile, and the warning is gone. No, MCC did not tell me to do this. It is not perfect or omniscient.
8. Flash the target
a) We are ready to download code to the target. I will assume that you have a suitable debugger / programmer, all the necessary adapters, and the target board is ready and powered up. In this case I also have a serial connection to my computer ready.
b) Click the green arrow on the top toolbar. This will build the project afresh and attempt to download the binary program.
c) This also launches the Debugger, but that is a topic for another blog.
9. Debugging (flash & crash way)
a) I’ll be honest, when I first built this, I had forgotten to set Redirect printf to UART in the UART1 settings. So I did not enjoy that magical ‘Hello World’ moment.
b) I did all the usual checks:
▪ The chip programmed fine. This is not always the case, especially with prototypes. But if ICSP can run, you know that you have Vdd and some rudimentary digital functionality.
▪ I had TeraTerm (my go-to serial monitor program) set to 115200 baud.
▪ On an oscilloscope I could see serial activity coming in on the RxD line when I banged on the keyboard.
▪ I remembered that, years ago, there was an environmental variable that one had to set, but attempting to insert that did not fix the problem.
▪ In serial.c I wrote a simple function:
void putChar1(char ch)
{
UART1_Write(ch);
while (!UART1_IsTxDone()) ;
}
▪ I prototyped this in serial.h and then called it in main.c. This worked fine, so I have a firmware problem.
▪ I reviewed my MCC setup, and sure enough, I simply had not asked for printf()to pipe to UART1. Easy ϐix. Click Generate. Click Clean & Build.
▪ Now I have a joyous ‘Hello World!’ in TeraTerm, and I am ready to move on.
Comments