I've been looking at the MPLAB Code Configurator to help set up the PIC16F enhanced range. It is known as MC² (hmmm). It is interesting, has a decent layout, helps quite a lot but I won't be using it very much at all.
Working on a laptop with the NetBeans IDE that the MPLAB X uses is a tight fit. Fitting all of the windows across the screen can be a bit awkward. MC² adds extra windows on tabs to increase the clutter, but is does it as well as can be expected and fits in the general layout theme well enough.
Firstly it lets you review and set the configuration bits of the micro controller. It reflects all of the configuration of the chosen micro controller and help select the system clock settings too. This is quick and useful.
It then allows you to include settings for each feature of the micro controller you want to use, including all of the GPIO. There is a pin manager view of the micro controller which shows you the package layout of your choice and which pins are used by the features you are using. GPIO pins can be renamed. Interrupts are set up where necessary. There is then a button to click to generate the code for the chosen options.
The code is generated in separate .h and .c files and, if you want it, a main.c is generated too which has all the includes and calls set up ready the main body to be added. The code all carries generated comments to help understand what the code does. All of the generated headers and code, except main.c, are in folders called MCC Generated Files to help find them.
When a GPIO pin is renamed a number of #defines in the headers use the name to allow more understandable code. For example if the portb pin 3 is renamed to LED then a #define LED_GetValue() is created to read the pin, LED_SetHigh(), LED_SetLow() and LED_toggle() are amongst the other #defines. The fact that these look like functions but are actually substituted as a small piece of code means the code will execute quickly, the stack won't over flow with too many calls and only code that is used will be incorporated by the compiler.
All of the other features are suitably handled, interrupt code is generated and so far all is well.
I said earlier that I won't be using this. It sounds, and is, useful so what is wrong?
All of the generated headers and code have a boilerplate licences on the front of them. It claims the code is written by Microchip Technology inc., which it is. This is followed by a bespoke licence making it clear that the code is only available to be used, modified, copied and distributed in an embedded on a Microchip controller. Under copyright law I could probably justify copying snippets in a post like this, but I cannot copy the code onto a code sharing service such as Github. The licence doesn't mention any time period - I would need it to be perpetual - so I don't know if Microchip will just revoke the licence in the future. Of course I could just ignore the licence and hope no one notices, or even just delete the boilerplate and pretend the code is mine, but that's not for me.
I dislike restrictive licences, so I won't be using or supporting it and I hope you don't either. MC² looks interesting and useful, but the licence is a serious obstacle.
Saturday, February 7, 2015
Tuesday, February 3, 2015
Enhanced mid-range
I had a browse through a comparison of Microchip's PIC microcontrollers and noticed the enhanced mid-range. I'm thinking about controlling some motors and some of these enhanced range have multiple PWM outputs. I bought a couple of PIC16F1827 to try.
I have been using the MPLab X IDE with XC8 C compiler on a laptop running Linux to program the PICs. I use Pickit 3 to send the code into the PIC and that is compatible with the enhanced PIC16s. I discovered the MPLAB Code Configurator which should help setting up the new PICs - it doesn't work with any of the old ones.
The enhanced range have various improvements, including being optimised for C code with a bigger instruction set, more interrupt lines, more input and output options, such as more analogue and PWM lines. It seems there is a more powerful internal clock, up to 32MHz on some PICs. If that works well, not needing an external crystal would be handy, not least because on small PICs that would free up two more GPIO pins.
I thought I'd set up a simple test bed and see what I can do.
I have been using the MPLab X IDE with XC8 C compiler on a laptop running Linux to program the PICs. I use Pickit 3 to send the code into the PIC and that is compatible with the enhanced PIC16s. I discovered the MPLAB Code Configurator which should help setting up the new PICs - it doesn't work with any of the old ones.
The enhanced range have various improvements, including being optimised for C code with a bigger instruction set, more interrupt lines, more input and output options, such as more analogue and PWM lines. It seems there is a more powerful internal clock, up to 32MHz on some PICs. If that works well, not needing an external crystal would be handy, not least because on small PICs that would free up two more GPIO pins.
I thought I'd set up a simple test bed and see what I can do.
Friday, November 16, 2012
Just too easy
One of the really nice things about Arduino is the way it connects to a PC. You can plug a simple USB cable between a laptop and the Arduino and it powers the board, allows the programs to be downloaded into the board and allows the board and the laptop to exchange info.
If you want an Arduino to control something mobile, then a wire to a laptop is a bit limiting. Plugging in to download a program change is OK, but sending commands or receiving feedback means that limiting cable. Except it doesn't.
I bought a little board with a 5V bluetooth module on it for a few pounds from Ebay. There are four connections, VCC & ground go where you would expect, Tx plugs onto the Rx pin (0) and Rx plugs onto Tx pin (1). You have to power it from the coax (or VIN) to release the transmit and receive pins from the USB connection. The coax works well with a 9V battery. A short sketch to read incoming characters and the on-board LED was switched with commands over bluetooth using the BlueTerm Android app. It worked first time.
I'd like to experiment some more with bluetooth, and I might write an Android app to make the phone end a bit more slick or purpose-made. The freedom from cables is wonderful.
If you want an Arduino to control something mobile, then a wire to a laptop is a bit limiting. Plugging in to download a program change is OK, but sending commands or receiving feedback means that limiting cable. Except it doesn't.
I bought a little board with a 5V bluetooth module on it for a few pounds from Ebay. There are four connections, VCC & ground go where you would expect, Tx plugs onto the Rx pin (0) and Rx plugs onto Tx pin (1). You have to power it from the coax (or VIN) to release the transmit and receive pins from the USB connection. The coax works well with a 9V battery. A short sketch to read incoming characters and the on-board LED was switched with commands over bluetooth using the BlueTerm Android app. It worked first time.
I'd like to experiment some more with bluetooth, and I might write an Android app to make the phone end a bit more slick or purpose-made. The freedom from cables is wonderful.
Wednesday, September 19, 2012
Extra interrupts
Once there is an interrupt routine, adding an extra interrupt is simple. In the last post there was only one thing causing an interrupt. There could have been any one of fourteen on a PIC16F873, so you need to check which interrupt has triggered, respond to it, reset the interrupt flag and return. I decided to add another to respond to the RB0 input. This pin can generate an interrupt on either a rising edge or a falling edge. I have tried both and it makes little difference, simply because I have a simple push switch that, like most switches, bounces. It switches on and off a few times as the button is pressed and even as the button is released. If a debounced switching system or real trigger such as a rotary encoder was being used then it would matter if the edge was rising or falling. The new interrupt routine is here:
The great thing about now having a millisecond timer built-in is we can use it anywhere we want. Here I set a timer to the current millisecond+2000 and we can use that in the master loop to switch an LED on for two seconds.
// ******* interrupt routine ********
interrupt void intrtn() {
/*
* interrupts all come here.
* First decide what caused the interrupt,
* then respond to it
*/
if (INTCONbits.T0IF) { // timer0 rolled
static uint16_t icount=0; // counts the timer clicks
icount+=512;
if (icount>1000) { // past a millisecond
++millis;
icount-=1000; // this preserves any error, which eventually smoothes out
}
INTCONbits.T0IF=0; // turn off int flag
}
if (INTCONbits.INTF) { // RB0 input fired
LEDoff=millis+2000; // turn of secends from now
INTCONbits.INTF=0;
}
}
The great thing about now having a millisecond timer built-in is we can use it anywhere we want. Here I set a timer to the current millisecond+2000 and we can use that in the master loop to switch an LED on for two seconds.
if (millis>LEDoff) {
manual_LED=0;
} else {
manual_LED=1;
}
Monday, September 17, 2012
Millisecond ticker
The last post was about making a background millisecond ticker and I can confirm that it works well. A quick test with a 500ms test that keeps alternating an LED give a 1Hz flash rate that seems to keep time with the tick of our clock, though I haven't tested it for very long. The millisecond timer will run for almost 50 days before it rolls over (32bit, unsigned integer) - if I wanted something to run longer I'd have to think of the best way to reset it to zero seamlessly (ideas are welcome).
I think I'll throw in another interrupt too to see how multiple interrupts get handled and too try to find any pit falls.
A picture of breadboard is here
and the existing code is below:
I think I'll throw in another interrupt too to see how multiple interrupts get handled and too try to find any pit falls.
A picture of breadboard is here
and the existing code is below:
/****************************************
* Description: dabbling with timers
*
* File: bresenham.c
* Author: Chris Hill
* Created: September 2012
*
* Using Bresenham's Algorithm to create a
* millisecond ticker
*
****************************************/
#include
#include
#pragma config BOREN = OFF, CPD = OFF, DEBUG = OFF, WRT = OFF, FOSC = XT, WDTE = OFF, CP = OFF, LVP = OFF, PWRTE = ON
#define _XTAL_FREQ 4000000
/***** GLOBAL VARIABLES *****/
#define manual_LED sPORTB.RB1
#define regular_LED sPORTB.RB2
#define manual_btn PORTBbits.RB3
volatile uint32_t millis; // millisecond counter, volatile because intrtn touches it
union {
uint8_t port;
struct {
unsigned RB0 : 1;
unsigned RB1 : 1;
unsigned RB2 : 1;
unsigned RB3 : 1;
unsigned RB4 : 1;
unsigned RB5 : 1;
unsigned RB6 : 1;
unsigned RB7 : 1;
};
} sPORTB;
void main() {
uint32_t nxtchange;
// initialisation
millis=0; // set the ticker to zero.
nxtchange=500; // set the next change point in milliseconds
//configure port & shadow
TRISB = 0b11111001;
PORTB=0;
sPORTB.port=0;
OPTION_REGbits.T0CS=0; // timer not counter
OPTION_REGbits.PSA=0; // use prescaler
OPTION_REGbits.PS2=0;
OPTION_REGbits.PS1=0;
OPTION_REGbits.PS0=0; // prescaler = 1:2
INTCONbits.T0IE=1; // timer0 interrupts on
ei(); // global interrupts are go
for (;;) {
if (millis>nxtchange) {
regular_LED=~regular_LED; // change the LED setting
nxtchange+=500; // ready for the next changeover
}
if (manual_btn) { // test switch to check chip is working
manual_LED=0;
} else {
manual_LED=1;
}
PORTB=sPORTB.port; // write out the port
}
}
// ******* interrupt routine ********
interrupt void intrtn() {
/*
* interrupts all come here.
* First decide what caused the interrupt,
* then respond to it
*/
// here timer0 is only interrupt
static uint16_t icount=0; // counts the timer clicks
icount+=512;
if (icount>1000) { // past a millisecond
++millis;
icount-=1000; // this preserves any error, which eventually smoothes out
}
INTCONbits.T0IF=0; // turn off int flag
}
Sunday, September 16, 2012
Timing using Bresenham's Algorithm
There are loads of reasons to time things, or wait for a specific time. If you want to wait for a specific time you can loop, doing nothing, until that time has elapsed. This can be useful, but it assumes the MCU is only doing one job. A better way it to count a time unit (such as a millisecond) in the background. Then you can get the current count, add the wait period and store the stop value, then keep checking in the main loop until the current count has exceeded the stored stop value. You will probably overshoot a little, but often this is OK. If you are trying to see if a button is pressed for, say, more than two seconds to respond to a long press, if you overshoot by a few micro seconds it makes no difference. If you are processing something regularly, such as displaying a timer, you can use the actual count time to check when the display should change. The nice thing is that you can use the count to test multiple wait or timer events independently. The snag is, how to build a reliable counter.
The PIC range have multiple timers, some of which get pressed into service for various jobs. Timer0 is always an 8 bit timer. It can either count external pulses (on a specific input pin) or increment each time the instruction cycle ticks. If an external crystal is used the instruction cycle runs at one quarter the crystal's frequency, so a 4MHz crystal means each instruction takes one one-millionth of a second and Timer0 will also increment at 1MHz. If the Timer0 is set running from zero, it will quickly reach 255 (in 255µs). At the next tick it will roll over to 0, so counting beyond 255 seems hard and 255µs is not that useful a length of time. The key is that as the timer rolls from 255 to 0, it can generate an interrupt.
An interrupt is a useful concept, when an interrupt is triggered the instruction the MCU is executing is finished, the address that the next instruction is at is stored (on the stack) and execution jumps to the interrupt address and continues there. When the interrupt code is complete it returns with a particular instruction which recovers the next address from the stack and jumps there to continue as if nothing has happened. Interrupt code must be short so as not to make everything else grind to a halt and it must not change the status registers so the original code really does continue unaffected. The XC-8 compiler for PICs handles the interrupt routine by letting you declare a function with the prefix interrupt. The function must be void and have no parameters and it shouldn't be called by anything else. XC-8 handles the saving and restoring of the status registers for you.
Now we have the means to use the Timer0 to generate ticks every 256µs (we need to set it up to do that) and that could be the basis of our count. Triggering an interrupt every 256µs is OK, if the code is very short, but it could be better if it was called less often - we are not going to be interested in approximately ¼ millisecond timing usually. Timer0 has a prescaler that is used as a divider to slowdown the rate at which the timer increments. If we use a prescaler of 4, the interrupt will fire every 1.024 milliseconds. We could use this as an approximation to a millisecond, and sometimes that is good enough. It would be possible to reset the Timer0 to count from a different number than 0, so counting from 250, four times gives exactly 1000, not 1024. This is fraught with problems, not least it adds a significant overhead to every interrupt routine, something to be avoided.
It would be acceptable to use a counter that is the number of 1024 ticks that have passed, but it is tempting to try to make a count in milliseconds. The counter and prescaler works in binary, so some sort of conversion is needed and a very neat one called Bresenham's Algorithm helps. This allows any difference between the counter and the target to be carried over and eventually smoothed out. To make the most of the prescaler we need to decide the resolution we want to count in. To count in 1ms units we need to use a prescaler that triggers the interrupt every 512µs, if we are happy to count in 2ms units we can use a prescaler that triggers every 1024µs.
The logic goes something like this:
So much for the theory, now lets see if I can make an LED flash at a reliable beat using this method ...
The PIC range have multiple timers, some of which get pressed into service for various jobs. Timer0 is always an 8 bit timer. It can either count external pulses (on a specific input pin) or increment each time the instruction cycle ticks. If an external crystal is used the instruction cycle runs at one quarter the crystal's frequency, so a 4MHz crystal means each instruction takes one one-millionth of a second and Timer0 will also increment at 1MHz. If the Timer0 is set running from zero, it will quickly reach 255 (in 255µs). At the next tick it will roll over to 0, so counting beyond 255 seems hard and 255µs is not that useful a length of time. The key is that as the timer rolls from 255 to 0, it can generate an interrupt.
An interrupt is a useful concept, when an interrupt is triggered the instruction the MCU is executing is finished, the address that the next instruction is at is stored (on the stack) and execution jumps to the interrupt address and continues there. When the interrupt code is complete it returns with a particular instruction which recovers the next address from the stack and jumps there to continue as if nothing has happened. Interrupt code must be short so as not to make everything else grind to a halt and it must not change the status registers so the original code really does continue unaffected. The XC-8 compiler for PICs handles the interrupt routine by letting you declare a function with the prefix interrupt. The function must be void and have no parameters and it shouldn't be called by anything else. XC-8 handles the saving and restoring of the status registers for you.
Now we have the means to use the Timer0 to generate ticks every 256µs (we need to set it up to do that) and that could be the basis of our count. Triggering an interrupt every 256µs is OK, if the code is very short, but it could be better if it was called less often - we are not going to be interested in approximately ¼ millisecond timing usually. Timer0 has a prescaler that is used as a divider to slowdown the rate at which the timer increments. If we use a prescaler of 4, the interrupt will fire every 1.024 milliseconds. We could use this as an approximation to a millisecond, and sometimes that is good enough. It would be possible to reset the Timer0 to count from a different number than 0, so counting from 250, four times gives exactly 1000, not 1024. This is fraught with problems, not least it adds a significant overhead to every interrupt routine, something to be avoided.
It would be acceptable to use a counter that is the number of 1024 ticks that have passed, but it is tempting to try to make a count in milliseconds. The counter and prescaler works in binary, so some sort of conversion is needed and a very neat one called Bresenham's Algorithm helps. This allows any difference between the counter and the target to be carried over and eventually smoothed out. To make the most of the prescaler we need to decide the resolution we want to count in. To count in 1ms units we need to use a prescaler that triggers the interrupt every 512µs, if we are happy to count in 2ms units we can use a prescaler that triggers every 1024µs.
The logic goes something like this:
volatile int millis;
millis=0;
...
// interrupt routine
interrupt void intrtn() {
static int icount=0;
icount+=512;
if (icount>1000) {
icount-=1000;
++millis;
}
// cleanup the interrupt stuff
}
So much for the theory, now lets see if I can make an LED flash at a reliable beat using this method ...
Driving motors works
Driving motors with PWM from midrange PICs works. There are 2 PWM outputs. They commandeer the Timer2 to control the signal timing. Working out what to set the timer bits to to get a given frequency and the duty cycle is a bit of arithmetic, but not too hard. I found a web site that helps you calculate it, plugging your required values in gives the required bit settings.
Using an Arduino is very, very much easier. There are six PWM outputs available and a single line of C code to set the duty cycle. The PWM frequency is fixed, so a less flexible. It is possible to change the frequency, but all the on-board timers get badly affected in the process.
If you want to drive more than two PWM with a PIC some of the PICF18 range have more PWM outputs. You could also output a simple signal on any pin controlling it yourself, but that would be a last resort for me, indeed I'd add another PIC first to get two more outputs.
Using an Arduino is very, very much easier. There are six PWM outputs available and a single line of C code to set the duty cycle. The PWM frequency is fixed, so a less flexible. It is possible to change the frequency, but all the on-board timers get badly affected in the process.
If you want to drive more than two PWM with a PIC some of the PICF18 range have more PWM outputs. You could also output a simple signal on any pin controlling it yourself, but that would be a last resort for me, indeed I'd add another PIC first to get two more outputs.
Subscribe to:
Posts (Atom)