Saturday, 22 September 2012

Pics have Timers

PICs come with hardware counters know as timers. I have just been playing with its timer features using the PicKit3 demoboard. The diagram below is taken from the PIC tutorial I am following.


There are some interesting things to note:

  • The timer has a prescaler
  • TMR0IF is the output and it needs to be cleared when set.
  • There is a complex arrangement for reading TMR0H
The timer has a prescaler
The prescaler allows us to divide the timers clock. In the example below their are two line of code (one commented out) That set the value of the prescaler.

 // Init Timer
    INTCONbits.TMR0IF = 0;          // clear roll-over interrupt flag
    //T0CON = 0b00001000;             // no prescale - increments every instruction clock
    T0CON = 0b00000001;             // prescale 1:4 - four times the delay.
    TMR0H = 0;                      // clear timer - always write upper byte first
    TMR0L = 0;
    T0CONbits.TMR0ON = 1;           // start timer

 TMR0IF is the output and it needs to be cleared when set.
We need to clear the output of the timer before we start it. The counter can be started using T0CONbits.

There is a complex arrangement for reading TMR0H
The high byte of the timer is no directly accessible. It can only be accessed in conjunction with the lower bytes. To read the timer always read TMR0L first then TMR0H. To write to the timer always write to TMR0H first then followed by TMR0L.

Reference
MicroChip PICkit3 Debug Express, PIC18F45k20 - MPLAB C Lessons. 

Friday, 21 September 2012

Rubik's Cube robot


I came across this video that uses iPhone and Lego Mindstorms to solve a Rubik's Cube.
Enjoy.


Wednesday, 19 September 2012

Switch Input












This post looks at lesson 4 of the Pic tutorial.


/** D E F I N I T I O N S ****************************************************/
#define Switch_Pin      PORTBbits.RB0
#define DetectsInARow   5

The # define in the .h file can be used to define meaningful names to the SFR register.



#pragma udata   // declare statically allocated uinitialized variablesunsigned char LED_Display;  // 8-bit variable
#pragma code    // declare executable instructions
void main (void)
{
    unsigned char Switch_Count = 0;
    LED_Display = 1;            // initialize
    TRISD = 0b00000000;     // PORTD bits 7:0 are all outputs (0)     INTCON2bits.RBPU = 0; // enable PORTB internal pullups     WPUBbits.WPUB0 = 1; // enable pull up on RB0      ANSELH = 0x00;              // AN8-12 are digital inputs (AN12 on RB0)      TRISBbits.TRISB0 = 1;       // PORTB bit 0 (connected to switch) is input (1)
    while (1)
    {
        LATD = LED_Display;     // output LED_Display value to PORTD LEDs
        LED_Display <<= 1;      // rotate display by 1
        if (LED_Display == 0)
            LED_Display = 1;    // rotated bit out, so set bit 0

        while (Switch_Pin != 1);    // wait for switch to be released
        Switch_Count = 5;
        do
        { // monitor switch input for 5 lows in a row to debounce
            if (Switch_Pin == 0)
            { // pressed state detected                Switch_Count++;
            }
            else
            {
                Switch_Count = 0;
            }
            Delay10TCYx(25);    // delay 250 cycles or 1ms.        } while (Switch_Count < DetectsInARow);
    }
}

Some of the pins are shared with the analog input to the pic and hence need to be configured as digital. The C code above is also used to debonce the mechanical switch.

---

I decided to try my hand at some simple refactoring to make the code more readable.


/** V A R I A B L E S *************************************************/
#pragma udata   // declare statically allocated uinitialized variables
unsigned char LED_Display;  // 8-bit variable
unsigned char Switch_Count = 0;
/** D E C L A R A T I O N S *******************************************/
#pragma code    // declare executable instructions
void main (void)
{
    InitOutputs();
    InitInputs();
    while (1)
    {
        SetOutputLedAndRotate();
        DebounceSwitchDetect();
    }
}

void InitOutputs(void)
{
    LED_Display = 0b10101010;            // initialize
    TRISD = 0b00000000;     // PORTD bits 7:0 are all outputs (0)
}
 

void InitInputs(void)
{
    INTCON2bits.RBPU = 0; // enable PORTB internal pullups
WPUBbits.WPUB0 = 1; // enable pull up on RB0
    ANSELH = 0x00;              // AN8-12 are digital inputs (AN12 on RB0)
    TRISBbits.TRISB0 = 1;       // PORTB bit 0 (connected to switch) is input (1)
}


void SetOutputLedAndRotate(void)
{
     LATD = LED_Display;     // output LED_Display value to PORTD LEDs
     LED_Display <<= 1;      // rotate display by 1
     if (LED_Display == 0)
        LED_Display = 3;    // rotated bit out, so set bit 0
}
 
void DebounceSwitchDetect(void)
{
  while (Switch_Pin != 1);  // wait for switch to be released
        Switch_Count = 5;
        do
        { // monitor switch input for 5 lows in a row to debounce
            if (Switch_Pin == 0)
            { // pressed state detected
                Switch_Count++;
            }
            else
            {
                Switch_Count = 0;
            }
            Delay10TCYx(25);    // delay 250 cycles or 1ms.
        } while (Switch_Count < DetectsInARow);
}



Wednesday, 12 September 2012

My Pic Microcontroller has some LEDs


Lesson 1: Hello LED
This blog post looks at doing nothing more that turning on and off the LEDs connected to port D of the PicKit3 demo board.






#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF, LVP = OFF, MCLRE = OFF
#include "p18f45k20.h"
void main (void)
{
TRISD = 0b01111111; // PORTD bit 7 to output (0); bits 6:0 are inputs (1) LATDbits.LATD7 = 1; // Set LAT register bit 7 to turn on LED
while (1);
}

The TRISD variable is used to access the tri-state for I/O on port D. LATDbits.LATD7 is used to access the seventh bit of port D. The code below uses  LATD instead of LATDbits.LATD7 to achiveve the same affect.


#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF, LVP = OFF, MCLRE = OFF
#include "p18f45k20.h"
void main (void)
{
TRISD = 0b01111111; // PORTD bit 7 to output (0); bits 6:0 are inputs (1)
        LATD = 0x80; while (1);
}

Lesson 2: BLINK LED
Configuration bits are used to set operating modes of enable disable different features of the Pic. The code below uses the configurations bits to set features such as the watch dog timer and the type of oscillator used.


#pragma config FOSC = INTIO67, FCMEN = OFF, IESO = OFF     // CONFIG1H
#pragma config PWRT = OFF, BOREN = SBORDIS, BORV = 30      // CONFIG2L
#pragma config WDTEN = OFF, WDTPS = 32768      // CONFIG2H
#pragma config MCLRE = OFF, LPT1OSC = OFF, PBADEN = ON, CCP2MX = PORTC  // CONFIG3H
#pragma config STVREN = ON, LVP = OFF, XINST = OFF    // CONFIG4L
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF             // CONFIG5L
#pragma config CPB = OFF, CPD = OFF      // CONFIG5H
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF    // CONFIG6L
#pragma config WRTB = OFF, WRTC = OFF, WRTD = OFF       // CONFIG6H
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF   // CONFIG7L
#pragma config EBTRB = OFF   // CONFIG7H
#include "p18f45k20.h"
#include "delays.h"
void main (void)
{
TRISD = 0b01111111; // PORTD bit 7 to output (0) ; bits 6:0 are inputs (1) while (1)
{
LATDbits.LATD7 = ~LATDbits.LATD7; // toggle LATD
Delay1KTCYx(500); // Delay 50 x 1000 = 50,000 cycles; 200ms @ 1MHz } }


The Delay1KTCYx(500) instruction is used to create a delay. The delay in this example is 200 ms and  is calculated as follows:

Delay = (No of Cycles to execute an instruction/Frequency)  x Delay in thousands of clock cycles x 1000

Delay = (4/1MHz) x 50 x 1000 = 200ms.

Lesson 3: Rotate LED

#pragma udata (uninitialized data) and #pragma idata (initialized data) are used to allocate memory for static variables in the file register. #pragma code  is used to indicate a section of instructions and #pragma romdata is used for constant data stored in program memory.


/** C O N F I G U R A T I O N   B I T S ******/                                       
/** I N C L U D E S **********************/
/** V A R I A B L E S ********************/#pragma udata // declare statically allocated uninitialized variablesunsigned char LED_Number;  // 8-bit variable
/** D E C L A R A T I O N S *******************************************/// declare constant data in program memory starting at address 0x180#pragma romdata Lesson3_Table = 0x180
const rom unsigned char LED_LookupTable[8] = {0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80};
#pragma code    // declare executable instructions
void main (void)
{
    LED_Number = 0;            // initialize    TRISD = 0b00000000;     // PORTD bits 7:0 are all outputs (0)
    while (1)
    {
// use lookup table to output one LED on based on LED_Number value        LATD = LED_LookupTable[LED_Number];  
        LED_Number++;      // rotate display by 1
        if (LED_Number == 8)
            LED_Number = 0;    // go back to LED 0.
        Delay1KTCYx(50);    // Delay 50 x 1000 = 50,000 cycles; 200ms @ 1MHz    } }




Reference
MicroChip PICkit3 Debug Express, PIC18F45k20 - MPLAB C Lessons.



Tuesday, 11 September 2012

I cant remember much about Pics


Harvard Architecture
The Microchip Pic microcontrollers are based on the Harvard Architecture. This means that the program and data memory are in separate address spaces i.e.  the each have their own address and data bus. In addition to program and data memory the stack also has its own dedicated memory which will allow 31 levels or subroutines.

Reset
On reset the address counter will be set to 0x000000. However the instruction placed at this address is normally a jump. The jump is used because the interrupt vectors sits at 0x000008 and 0x000018.

Memory Modes
Transparent to a C programmer the Pic can have two memory modes small and large and some areas program memory can be protected to keep your design from others eyes.

File Register
The Pic has between 4K and 8K of data memory, known as the File Register. The data is organised into 256k banks that can be accessed using a bank select register. There are areas in Bank0 and Bank15 that can be accessed without the need of swapping banks. This is known as Access Ram and contains the Special Function Registers. Again this is transparent to the C programmer.

Sunday, 9 September 2012

Pacemaker Finished


I have just finished the Doulos (http://www.doulos.com) VHDL Tutorial called Pacemaker. The notes I made while working through the tutorial can be found in this blog and cover:
  1. VHDL State Encoding
  2. VHDL No Output Decoding Logic
  3. VHDL SM Separating Registers
  4. Explicit State Machine
  5. VHDL Variables & Registers
  6. VHDL The Five Process Styles
  7. VHDL FF using Wait Unitil
  8. Flip Flop with Enable
  9. VHDL Technology Dependent Components
  10. VHDL Asynchronous FF Reset
  11. VHDL Edge Triggered Flip Flop
  12. VHDL Transparent Latch
  13. VHDL Conversion Functions
  14. Synthesis if Arithmetic Operators
  15. VHDL Operator Overloading
  16. VHDL Std_Logic_Vector
  17. VHDL Constant
  18. VHDL Logical Operators
  19. VHDL Enumeration Types
  20. VHDL Equivalent Concurrent Statments
  21. VHDL Test Bench Clock
  22. VHDL While, Loop, Exit, Next
  23. VHDL For Loop
  24. VHDL Case Statment
  25. VHDL Incomplete Assignments
  26. VHDL IF Statment
  27. VHDL Variables
  28. VHDL Signal Assignment
  29. VHDL Test Vectors using Wait
  30. VHDL Wait
  31. VHDL Sensitivity List
  32. VHDL Process
  33. VHDL Configurations
  34. VHDL Test Bench
  35. VHDL STD_LOGIC
  36. VHDL Design Entity Referance
  37. VHDL Component Declaration and Instantiation
  38. VHDL Concurrent Signal Assignmants
  39. VHDL Signals
  40. VHDL Design Entity


VHDL State Encoding


type StateType is
         (Idle, Start, Stop, Clear);
signal State: StateType;


The states will be encoded as below. We can change the encoding by changing the order in the type statement.
Idle = 00
Start = 01
Stop = 01
Clear = 11

However some synthesis tools can be told to optimize the SM automatically. Do not turn on this option if you want to be in full control.

----
Unreachable states are created with the following type def.


type StateType is
         (One, Two, Three, Four, Five);

This is ok but if you want to specify what happens specify the dummy states you can create this as follows:

type StateType is
         (One, Two, Three, Four, Five,
          Dummy1, Dummy2, Dummy3);



Reference

This blog post contains notes taken when working through the Doulos Pacemaker tutorial.   Any content copied from the tutorial has been reproduced with permission.  http://www.doulos.com.