Friday 20 July 2012

Timers and interrupts

Yoikes, over a year since I last looked into this project... Time passes so quickly, I blame real life sadly along with a few computer games too including Star Wars amongst others...  So anyway someone at work was talking about programming at home and as a result it got me interested again in the microprocessor project...

When I last left you I had been trying to get Timer interrupts to work and after a few hours of trying to copy samples and not actually getting anywhere I decided to have another look at it.  And this time YAY I managed to get a timer to cause an interrupt.  So I'll go through code and see if I can explain it all as I go...

First the plan is to have a main program just flashing the status LED, while we have a timer interrupt which increases a counter and then display the last four bits of that counter as a hex number on the LED display.

Originally I tried to get TIMER0 to work, however for some reason, (I think it was because I needed an external clock or something), timer0 didn't seem to be workable and so I changed to using the Timer1 counter to count clock cycles and increment the LED display each time the counter ticks over.  Of course it helped when I finally realised that I needed to turn on the interrupt processing as well as turning on the Timer modules.

;******************************************************************************
; Filename:      Timer_Interrupt.asm                                          *
; Date:          20th July 2012                                               *
; Author:        M.J.Andrews                                                  *
;******************************************************************************

 LIST P=18F2455, F=INHX32  ; Directive to define processor
#include <P18F2455.INC>    ; Processor specific variable definitions
#include <LED_Segment.INC> ; LED Segment Macro's


We'll still use the same old LED segment setting include file and the default P18F2455 include file to define all the constants we're going to want to be using.

;******************************************************************************
; Configuration bits

 CONFIG FOSC = INTOSC_HS ;HS - HS OSCILLATOR

Still using the internal oscillator

;******************************************************************************
; Variable definitions

  UDATA
WREG_TEMP   RES 1  ; Variable in RAM for context saving
STATUS_TEMP   RES 1  ; Variable in RAM for context saving
BSR_TEMP   RES 1  ; Variable in RAM for context saving


  UDATA_ACS
CNT_INNER   RES 1  ; Delay procedure, Inner Loop Count
CNT_OUTER   RES 1  ; Delay procedure, Outer Loop Count
CNT_TIMER   RES 1  ; Timer Interrupt counter


We need variables to store the old values in the various registers while the interrupt service routines run.  We also keep the inner and outer counters for our delay procedure from before and also a new counter which we will increment on each timer interrupt.

;******************************************************************************
; Reset vector's

RESET_VECTOR CODE 0x0000
  goto Main ; Go to start of main code
HI_INT_VECTOR CODE 0x0008
  bra HighInt  ; Go to high priority interrupt routine
LOW_INT_VECTOR CODE 0x0018
  bra LowInt  ; Go to low priority interrupt routine


Standard code to provide the appropriate commands to point to the appropriate code points when starting u or receiving any high or low priority interrupt.

;******************************************************************************
;****                  Start of the Program Code Section                   ****
;******************************************************************************

  CODE

;******************************************************************************
; High priority interrupt routine
;******************************************************************************
HighInt:
 MOVWF WREG_TEMP           ; Save working register
 MOVFF STATUS,STATUS_TEMP  ; Save STATUS register
 MOVFF BSR,BSR_TEMP        ; Save BSR register


 MOVFF CNT_TIMER, WREG     ; Copy the current counter to W-REG
 CALL  DisplaySegments     ; Display bottom 4 bits of the counter
 INCF  CNT_TIMER, F        ; Increment the timer interrupt counter

 BCF   PIR1, TMR1IF        ; Clear interrupt flag so ints continue
 MOVFF  BSR_TEMP,BSR       ; Restore BSR register
 MOVFF  WREG_TEMP,WREG     ; Restore working register
 MOVFF  STATUS_TEMP,STATUS ; Restore STATUS register
 RETFIE FAST


Start the main code section with the High-priority interrupt routine.  This starts by saving a number of registers which could contain data at the time of the interrupt.  We then update the display segment with the number currently in the counter which we then increment.  Clearing the interrupt flag lets the program continue and we then return the registers to their previous state, (hmmmm should the TMR1IF clear happen after returning the interrupts).  Finally we return from the interrupt.

;******************************************************************************
; Low priority interrupt routine
;******************************************************************************
LowInt:
 RETFIE


We skip the low priority interrupt as we;re not using it

;******************************************************************************
;****                           M A I N   C O D E                          ****
;******************************************************************************

Main:

Initialize
 BCF   TRISA, TRISA0  ; RA0 as an output for the "working" led
 BCF   TRISB, TRISB0  ; RB0 as an output for the 7-segment LED
 BCF   TRISB, TRISB1  ; RB1 as an output for the 7-segment LED
 CLRF  WREG           ; Clear the Working Register
 MOVWF TRISC          ; W-REG to PORTC to set as all outputs


We initialise the registers so we can output the LED segments and the status led.

 BSF   OSCCON, IRCF2  ; Set the internal Fosc value to "111"
 BSF   OSCCON, IRCF1  ; which I believe results in an 8Mhz
 BSF   OSCCON, IRCF0  ; clock speed according to the specs


 I noticed that there were three bits to set the internal oscillator speed which I set to "111" which may mean an 8Mhz clock speed, (although I need to check that).

 RTCinit
 ; Default the start values for the counters
 CLRF CNT_TIMER      ; Initialize interrupt counter
 CLRF TMR1H          ; Start with a zero high bit (no update)
 CLRF TMR1L          ; Start with a zero low bit (& updates TMR0H)


 ; Set the base Interrupt registers to turn interrupts on
 BSF  RCON,  IPEN    ; Set IPEN bit to enable priority interrupts
 BSF  INTCON, GIEH   ; Set GIEH bit to enable high prio ints
 BCF  INTCON, GIEL   ; Clear GIEL bit to disable low prio ints


 ; Configure the TIMER1 settings
 MOVLW b'00110001'   ; Set T1CON settings
                     ;  * RD16    = 0 - 8-bit TIMER0 count
                     ;  * T1RUN   = 0 - Clocked from ext source
                     ;  * T1CKPS1:T1CKPS0 = 11 - 1:8 prescaling
                     ;  * T10SCEN = 0 - Timer1 Oscillator off
                     ;  * T1SYNC  = X - N/A with TMR1CS at 0
                     ;  * TMR1CS  = 0 - Internal Clock (Fosc/4)
                     ;  * TMR1ON  = 1 - Turn Timer1 on!
 MOVWF T1CON         ; Set the T1CON from W-Reg set last command

 BSF  PIR1, TMR1IF   ; Timer1 Flag Bit
 BSF  IPR1, TMR1IP
 BSF  PIE1, TMR1IE   ; Timer1 Enable Bit


 SET_SEGMENT_TO_0

See the comments in the code above, but basically this initialises the timer and interrupt processing so that it all works...  Finally strart the LED segment with a display of "0".

Start_Loop
 TOGGLE_STATUS_LED
 call Delay        ; Call the delay procedure so we see value
 goto Start_Loop   ; Go back to the start of the loop


This is the main loop, it toggles the LED and then runs the delay procedure I used previously, (I copied this into the code file but won't re-show it here).  After delaying this then goes back up to toggle the led again.

After all this playing I have the status LED flashing away while the LED segment counts up from 0 to F repeatedly over a constant time period showing that the interrupt is working correctly.  It took a while but I'm glad I'm at this point.  I now want to try and get the USB interface to work... Hopefully sometime in the next year this time though!

Monday 7 March 2011

Timer Module stuff...

Another weekend away, and I've not managed to get very far onwards. I've read a number of data sheet entries and sample programs in my time away.  Little things like finding out that numbers starting with a full stop (e.g. ".123") are decimal values.  Binary values can be displayed as b'11110000'.

Also there seem to be a number of commands which exist within the MASM compiler to make coding easier.  For example it is possible to use the command "variable xyz" to make a variable instead of having to assign bytes to variables in the data section...

I did even try a bit of code in the DisplaySegments procedure:

 variable TEST_VAR
 andlw 0x0F
 movff WREG, TEST_VAR
 goto $ + (4 * TEST_VAR)


Unfortunately this didn't work, I still wonder if it is possible, since "goto $ + 8" does work, it may just be static references which work...

Monday 28 February 2011

LED Segment Counter

After a little playing with the program, I've now managed to get the program to count up from 0 to F, then back to 0, while toggling the processing LED every time the LED display is changed.  While this may be a simple program, it did teach me a few things about how to jump around code, (in order to display the value based on an entry in the working register there had to be the value multiplied by 4, then added to the Program Counter).

There's not much I can really say, other than posting the code, which doesn't quite feel like the place here to post, however I may as well post it, although the formatting may be a bit out where tabs are just transferred as spaces. 

So anyway, the Macro Include file, (I put Macro's into a different include file):

;***********************************************************************
; Filename:      LED_Segment.inc
; Date:          28th February 2011
; Author:        M.J.Andrews
; Purpose:       Program to contain macro's for the LED Segment program.
;***********************************************************************

;***********************************************************************
;****                        M A C R O ' S                         ****
;***********************************************************************

; ----------------------------------------------------------------------
; Macro   : TOGGLE_STATUS_LED
; Purpose : Macro to toggle the processing LED.  This is kept flashing
;           while we run the program as it shows that the processor is
;           working correctly and make it obvious if the code gets stuck.
; ----------------------------------------------------------------------
TOGGLE_STATUS_LED MACRO
 btg  LATA, RA0    ; Toggle the LED status
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_LATC
; Purpose : Macro to set the value of the LATC byte which is most of the
;           7-segment display entries.  We also toggle the status LED so
;           that we can see the LED flash to show the processor running.
; ----------------------------------------------------------------------
SET_LATC MACRO LATCValue
 TOGGLE_STATUS_LED
 MOVLW  LATCValue
 MOVWF  LATC
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_0
; Purpose : Set the LED 7-Segment display to "0"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_0 MACRO
 SET_LATC 0x80
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_1
; Purpose : Set the LED 7-Segment display to "1"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_1 MACRO
 SET_LATC 0xFB
 bcf  LATB, 0
 bsf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_2
; Purpose : Set the LED 7-Segment display to "2"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_2 MACRO
 SET_LATC 0x44
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_3
; Purpose : Set the LED 7-Segment display to "3"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_3 MACRO
 SET_LATC 0x41
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_4
; Purpose : Set the LED 7-Segment display to "4"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_4 MACRO
 SET_LATC 0x03
 bcf  LATB, 0
 bsf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_5
; Purpose : Set the LED 7-Segment display to "5"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_5 MACRO
 SET_LATC 0x01
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_6
; Purpose : Set the LED 7-Segment display to "6"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_6 MACRO
 SET_LATC 0x00
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_7
; Purpose : Set the LED 7-Segment display to "7"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_7 MACRO
 SET_LATC 0xFB
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_8
; Purpose : Set the LED 7-Segment display to "8"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_8 MACRO
 SET_LATC 0x00
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_9
; Purpose : Set the LED 7-Segment display to "9"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_9 MACRO
 SET_LATC 0x01
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_A
; Purpose : Set the LED 7-Segment display to "A"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_A MACRO
 SET_LATC 0x02
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_B
; Purpose : Set the LED 7-Segment display to "b"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_B MACRO
 SET_LATC 0x00
 bsf  LATB, 0
 bsf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_C
; Purpose : Set the LED 7-Segment display to "C"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_C MACRO
 SET_LATC 0x8C
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_D
; Purpose : Set the LED 7-Segment display to "d"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_D MACRO
 SET_LATC 0x40
 bcf  LATB, 0
 bsf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_E
; Purpose : Set the LED 7-Segment display to "E"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_E MACRO
 SET_LATC 0x04
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_F
; Purpose : Set the LED 7-Segment display to "F"
; ----------------------------------------------------------------------
SET_SEGMENT_TO_F MACRO
 SET_LATC 0x06
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM

; ----------------------------------------------------------------------
; Macro   : SET_SEGMENT_TO_CLEAR
; Purpose : Set the LED 7-Segment display to blank with no LED's lit
; ----------------------------------------------------------------------
SET_SEGMENT_TO_CLEAR MACRO
 SET_LATC 0xFF
 bsf  LATB, 0
 bsf  LATB, 1
 ENDM
And the main application file:

;******************************************************************************
; Filename:      LED Segment.asm                                              *
; Date:          28th February 2011                                           *
; Author:        M.J.Andrews                                                  *
;******************************************************************************

LIST P=18F2455, F=INHX32 ; Directive to define processor
#include <P18F2455.INC>  ; Processor specific variable definitions
#include <LED_Segment.INC> ; Macro's for use with this program

;******************************************************************************
; Configuration bits

CONFIG FOSC = INTOSC_HS ;HS - HS OSCILLATOR
;******************************************************************************
; Variable definitions

  UDATA
WREG_TEMP   RES 1  ; Variable in RAM for context saving
STATUS_TEMP   RES 1  ; Variable in RAM for context saving
BSR_TEMP   RES 1  ; Variable in RAM for context saving

  UDATA_ACS
CNT_INNER   RES 1  ; Delay procedure, Inner Loop Count
CNT_OUTER   RES 1  ; Delay procedure, Outer Loop Count
LED_SEGMENT_DISP RES 1  ; LED Segment counter variable

;******************************************************************************
; EEPROM data

DATA_EEPROM CODE 0xf00000
  DE "Test Data",0,1,2,3,4,5
;******************************************************************************
; Reset vector's

RESET_VECTOR CODE 0x0000
  goto Main ; Go to start of main code
HI_INT_VECTOR CODE 0x0008
  bra HighInt  ; Go to high priority interrupt routine
LOW_INT_VECTOR CODE 0x0018
  bra LowInt  ; Go to low priority interrupt routine

;******************************************************************************
;****                  Start of the Program Code Section                   ****
;******************************************************************************

  CODE
;******************************************************************************
; High priority interrupt routine
;******************************************************************************
HighInt:
  retfie FAST

;******************************************************************************
; Low priority interrupt routine
;******************************************************************************
LowInt:
  movff STATUS,STATUS_TEMP ;save STATUS register
  movff WREG,WREG_TEMP  ;save working register
  movff BSR,BSR_TEMP  ;save BSR register

; *** low priority interrupt code goes here ***
  movff BSR_TEMP,BSR  ;restore BSR register
  movff WREG_TEMP,WREG  ;restore working register
  movff STATUS_TEMP,STATUS ;restore STATUS register
  retfie

;******************************************************************************
;****                           M A I N   C O D E                          ****
;******************************************************************************

Main:
Initialize
 bcf  TRISA, TRISA0   ; RA0 as an output for the "working" led
 bcf     TRISB, TRISB0   ; RB0 as an output for the 7-segment LED
 bcf     TRISB, TRISB1   ; RB1 as an output for the 7-segment LED
 clrf WREG     ; Clear the Working Register
 movwf TRISC     ; W-REG to PORTC to set as all outputs

 movlw 0x00     ; Start with 0 in the Working Register
 movwf LED_SEGMENT_DISP  ; Move the 0 to the Segment counter

Start_Loop
 movff LED_SEGMENT_DISP, WREG ; Copy the value of the counter to W-REG
 call DisplaySegments   ; Call proc to display LED value in W-REG
 call Delay     ; Call the delay procedure so we see value
 incf LED_SEGMENT_DISP  ; Increment the LED counter
 goto Start_Loop    ; Go back to the start of the loop

;******************************************************************************
;****                          P R O C E D U R E S                         ****
;******************************************************************************

; ----------------------------------------------------------------------
; Function: DisplaySegments
; Purpose : Procedure which can be called to display the low 4-bit value
;           from the W-REG as a numeric value on the LED 7-Segment display.
; ----------------------------------------------------------------------

DisplaySegments
 andlw 0x0F     ; Ensure the value in W-REG is 0->F
 mullw 0x04     ; Multiply W-REG to see how far to jump
 movff PRODL, WREG    ; Move the result back to the W-REG

 addwf PCL      ; Add the value to the Program counter
         ; This will skip forward to the goto
         ; command below to display the LED's
 goto  DISP_0
 goto  DISP_1
 goto  DISP_2
 goto  DISP_3
 goto  DISP_4
 goto  DISP_5
 goto  DISP_6
 goto  DISP_7
 goto  DISP_8
 goto  DISP_9
 goto  DISP_A
 goto  DISP_B
 goto  DISP_C
 goto  DISP_D
 goto  DISP_E
 goto  DISP_F

DISP_0 SET_SEGMENT_TO_0   ; Use the Macro to set the LED to '0'
  return
DISP_1 SET_SEGMENT_TO_1   ; Use the Macro to set the LED to '1'
  return
DISP_2 SET_SEGMENT_TO_2   ; Use the Macro to set the LED to '2'
  return
DISP_3 SET_SEGMENT_TO_3   ; Use the Macro to set the LED to '3'
  return
DISP_4 SET_SEGMENT_TO_4   ; Use the Macro to set the LED to '4'
  return
DISP_5 SET_SEGMENT_TO_5   ; Use the Macro to set the LED to '5'
  return
DISP_6 SET_SEGMENT_TO_6   ; Use the Macro to set the LED to '6'
  return
DISP_7 SET_SEGMENT_TO_7   ; Use the Macro to set the LED to '7'
  return
DISP_8 SET_SEGMENT_TO_8   ; Use the Macro to set the LED to '8'
  return
DISP_9 SET_SEGMENT_TO_9   ; Use the Macro to set the LED to '9'
  return
DISP_A SET_SEGMENT_TO_A   ; Use the Macro to set the LED to 'A'
  return
DISP_B SET_SEGMENT_TO_B   ; Use the Macro to set the LED to 'b'
  return
DISP_C SET_SEGMENT_TO_C   ; Use the Macro to set the LED to 'C'
  return
DISP_D SET_SEGMENT_TO_D   ; Use the Macro to set the LED to 'd'
  return
DISP_E SET_SEGMENT_TO_E   ; Use the Macro to set the LED to 'E'
  return
DISP_F SET_SEGMENT_TO_F   ; Use the Macro to set the LED to 'F'
  return

; ----------------------------------------------------------------------
; Function: Delay
; Purpose : Procedure to wait roughly 128*255 program cycles before
;           continuing, so that we can see the changes of the LED's
; ----------------------------------------------------------------------

Delay
 movlw 0x80            ; Initialize outer loop counter (0x40 - 128)
 movwf CNT_OUTER,A     ; Set outer loop variable to the counter
DelayOuter
 movlw 0xFF            ; Initialize inner loop counter (0xFF - 255)
 movwf CNT_INNER,A     ; Set inner loop variable to the counter
DelayInner
 decfsz CNT_INNER,F,A   ; Decrease Inner counter, skip next on 0
 goto DelayInner      ; Go to the next Inner count, (NOP on 0 CNT_INNER)
DelayInner_End
 decfsz CNT_OUTER,F,A   ; Decrease Outer counter, skip next on 0
 goto DelayOuter      ; Go to the next Outer count, (NOP on 0 CNT_OUTER)
DelayOuter_End
 return                  ; Return back to the place which called this proc

;******************************************************************************
;****                      E N D   O F   P R O G R A M                     ****
;******************************************************************************
  END

And the current circuit diagram as updated in KiCAD for the current version.

Checking through the DMX connector's

I arrived back from my weekend away to find that the cables and connector's I'd ordered had arrived in the post from Canford.  Before I describe the bits, I should say I found the location to get stuff from when I stumbled accross the a USB to DMX website.  In this site, the connector they use is an XLR socket "NC5FDM3H" from Canford code 40-583, and I thought I may as well use this part as they come from a working system.

Unfortunately since I failed on two counts with my order, I seem rather inept at ordering what I want!  Firstly I got three 3-pin connector's, 2 female, one male.  And secondly all of the connectors I got were vertical mounting, not horizontal which is what I was expecting!  Of course if I'd have been thinking enough I'd have realised this before!  So lets look at the part number used, "NC5FDM3H"...

First it looks like the "NC5" is the important bit for a 5-pin connector, (not the M3 on the letters near the end of the reference, as I thought since the image of the M3-H on the website had 5 pins).  Secondly, despite the website saying Horizontally mounted pins, I for some reason went and got vertically mounting ones!

While this doesn't matter in the grand scheme of things since I'll just solder some wires to the connectors, and the lights I plan on getting all require 3-pin connector's anyway, it is still a little annoying!

It turns out the M3 version of the connector has M3 threaded holes in the connecting plate so that it can be behind the plastic outside with a bolt through, while the other one has counter-sunk holes.  Of these, I definitely prefer the M3 version because it means that only the socket and screws will be visible.

Anyway here's the picture of the bits I got:


I had anopther N00B moment while looking at the individual connector's trying to figure out how they can be 'locked' into place.  Eventually I realised that the entrance to the hole you can use a tiny screwdriver to turn the locking mechanism is actually at the front of the socket, not the back!  Also it appears as though there is a fourth pin which is there purely so the locking mechanism doesn't get lost when unlocked, the pin appears removable once the component is all installed and locked properly.




Top Left: Female 3-Pin socket
Top Right: View of the pins for the socket
Bottom Left: You can just about see the screwdriver shaped slot in the 4th hole
Bottom Right: Opening the socket when unlocked

Friday 25 February 2011

DMX Cables & LED Segment

Last night I decided to get round to buying two cables, a 3-pin and a 5-pin female PCB socket connector, along with one 3-pin male connector.  I could have got the cables as a length of wire, and a few end pieces but I was feeling a bit lazy.  Two wires should be plenty for testing the DMX lights I'm going to buy in a bit, (the local theatre is buying some cheap LED parcans for the next show so I've said I'll buy two back after the show so they can reduce the budget and so I can get two lights to play with).. The LED pars have 3-pin DMX connectors, hence the 3-pin stuff.  The 5-pin is because I believe that is the proper DMX connector.  2 wires to plug DMX from the circuit to one light, then the second for the wire between the two lights.

The company phoned this morning saying they didn't have 2meter cables in black, so I changed it to a red and a blue ire instead.  I'd have preferred black, but when it comes to it they are only really meant for testing.

Anyway I'm off for an extended weekend, hence the day off work.  I've been thinking about my problem setting the PortB bits on the circuit and programming in the LED segment.  While I may be in a bit of a rush, I thought Meh, and sat down for an hour...

A little searching on the Microchip site shows that I should be setting the "LATB" register when I'm using the bsf and bcf methods to stop any inputs interferring or something...  Changing that and it solved all my previous problems trying to set those LED segments, (wierd how something so simple wastes so much time).

Anyway I've now coded a few macro's based on how I've wired the chip at the moment so I can use the Macro's to set the LED segment to match a certain entry.  It's a shame I couldn't use one full 8-bit port really as that would have meant just two processor instructions to set the segment.  As it is, I need four, (and thinking about it maybe I should be using LATC instead of PORTC when setting it to a byte, however for now the macro's for the segment settings is shown below:

SET_PORTC MACRO PortCValue
 MOVLW  PortCValue
 MOVWF  PORTC
 ENDM


SET_SEGMENT_TO_0 MACRO
 SET_PORTC 0x80
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_1 MACRO
 SET_PORTC 0xFB
 bcf  LATB, 0
 bsf  LATB, 1
 ENDM


SET_SEGMENT_TO_2 MACRO
 SET_PORTC 0x44
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_3 MACRO
 SET_PORTC 0x41
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_4 MACRO
 SET_PORTC 0x03
 bcf  LATB, 0
 bsf  LATB, 1
 ENDM


SET_SEGMENT_TO_5 MACRO
 SET_PORTC 0x01
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_6 MACRO
 SET_PORTC 0x00
 bsf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_7 MACRO
 SET_PORTC 0xFB
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_8 MACRO
 SET_PORTC 0x00
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_9 MACRO
 SET_PORTC 0x01
 bcf  LATB, 0
 bcf  LATB, 1
 ENDM


SET_SEGMENT_TO_CLEAR MACRO
 SET_PORTC 0xFF
 bsf  LATB, 0
 bsf  LATB, 1
 ENDM
I then wrote a little counter program to cycle through each of the numbers and blank entries listed above:

Start_Num_Loop
 SET_SEGMENT_TO_CLEAR
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_0
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_1
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_2
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_3
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_4
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_5
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_6
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_7
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_8
 call Delay           ; Call the Delay procedure to wait a bit
 SET_SEGMENT_TO_9
 call Delay           ; Call the Delay procedure to wait a bit


Anyway that will do for now, no time to make it show A-F, and to use a slider as an input... Next time!

Wednesday 23 February 2011

Crystal Oscillator and LED 8-Segment display

Another evening, and after originally thinking about ordering some Sockets and Cables for when I eventually get onto outputting DMX, instead I started rooting through my electronics toolbox and found another Crystal, and another of the sliding potentiometers, (100K resistance it turns out)...

So I took the crystal, added the same capacitors I had previously, and added them to the circuit board.  I had to change the oscillator setting in the program to "HS", re-make, program and run the old circuit and yup, the LED flashes a lot lot faster...


The image above shows the crystal and capacitors added to the circuit.  Since the HS Oscillator setting is a little too fast for what I'm doing at the moment I changed it back to "INTOSC_HS" which is meant to be the internal oscillator for program and HS for USB.  Either way it's back to the internal oscillator for now.

Looking at the slider I had, the connection pins fit in nicely to the bread board, but there are four exra pins which I think are meant to be used to fix the slider on to a PCB board... Since I was thinking of programming in the slider again to show how to read inputs I needed to bend those pins back as shownb below:


However thinking about connecting the slider up, I don't actually have any method of telling where the slider is, except for perhaps changing the flash rate of the led... So since I have an 8-segment LED display in the box of LED's, perhaps I should wire that up and use that to display some numbers or letters based on the slider location.

First I needed to find out how to how to wire the LED segment.  A little investigation shows a common +ve connected to pin 3 or 8, and I found all my 1K resistors, so some quick testing to check it out...


So LED's will be on when a pin is set to output and has a value of 0, a value of 1 being off.  The question is where to connect the pions to on the chip... At first I thought to use PORTC as the pins are all down the bottom of the chip, and there are only 7 pins available, (I'm not going to use the decimal point so 7 not 8).

After connecting the segments up to the chip I found that I couldn't figure out how to set two pins, (apparently they could be configured to be outputs if the USB is turned off in one register, but I still failed to get them to output)... In the end I connected two bits from Port B in instead, and then had more fun failing to get those to work as expected... I think I must be using the wrong assembly command to set bits directly as setting the whole PORTB value worked, but not using bcf and bsf...

I have a feeling that I realised the 'obvious' bit set and clear commands didn't do what I expected them to do when I was last trying to learn assembly.  Something to look at later, I've had enough for this evening.  So here's the board layout I had at the end of my fiddling, while the connections are not ideal, for now they're all fine.


At least it looks fairly neat and tidy... Yes I could have just thrown in any old wires, but I like wires all being the right length.. Maybe a bit OCDish, but at least you can follow the wires easily.  If it was wires all-over the place then it can very easily become very confusing!

Oh one thing I almost forgot to say... Trying to connect the board direct to power seems to fail now for some reason, so I must have messed up something somewhere, but it all still works when the programmer is connected with the RESET cleared... so probably something linked to that and maybe the Oscillator... Something to look at another day!

Tuesday 22 February 2011

Flashing LED

Well I'm going out to one of the weekly theatre set build evenings in an hour, so just enough time to update the program so that we can flash the LED...  A little lookign through the assembly commands, and looking back at some of my old applications which were probably based on the PICkit examples, I did the following:

1) Added two new variables so we can have a loop which loops a certain number of times before we next change the LED.  Since the Processor will be running many many commands a second, we need to wait a number of oscillator ticks before changing the LED state.  So adding two variables after the UDATA_ACS line:

  UDATA_ACS
CNT_INNER RES 1 ; Inner Loop Count
CNT_OUTER RES 1 ; Outer Loop Count


2) Added code to the Mains ection of the program which initializes the LED, (we have that code already), then to turn the LED on, followed by a call to a Delay procedure to wait a bit.  This is followed by turning the LED off and another delay procedure call...

Main:
Initialize
 clrf WREG            ; Clear the W-Register
 movwf TRISA          ; W-REG to PORTA to set as all outputs

Turn_LED_ON
 movlw 0xFF           ; Set all bits in the WREG
 movwf PORTA          ; Update PORTA to turn the LED on
 call Delay           ; Call the Delay procedure to wait a bit

Turn_LED_OFF
 clrf WREG            ; Clear the WREG
 movwf PORTA          ; Update PORTA to turn the LED off
 call Delay           ; Call the Delay procedure to wait a bit

 goto Turn_LED_ON     ; Go back to the LED ON for an Infinite loop

3) Of course we then need to have the Delay procedure somewhere, so I'll place it after the command to go back to the turning the LED on label...

Delay
 movlw 0x40            ; Initialize outer loop counter (0x40 - 128)
 movwf CNT_OUTER,A     ; Set outer loop variable to the counter
DelayOuter
 movlw 0xFF            ; Initialize inner loop counter (0xFF - 255)
 movwf CNT_INNER,A     ; Set inner loop variable to the counter
DelayInner
 decfsz CNT_INNER,F,A  ; Decrease Inner counter, skip next on 0
 goto DelayInner       ; Go to the next Inner count, (NOP on 0 CNT_INNER)
DelayInner_End
 decfsz CNT_OUTER,F,A  ; Decrease Outer counter, skip next on 0
 goto DelayOuter       ; Go to the next Outer count, (NOP on 0 CNT_OUTER)
DelayOuter_End
 return                ; Return back to the place which called this proc


Compiling it, it succeeded!  So program the chip, then release from reset, and yay a flashing LED...