External Links

Creative Science Centre

 

Interrupts

This section deals with the interrupts at register level rather then using the 'rookie' firmware.

ByPic keeps a table of all of the interrupts that need to be serviced, UART 1 and 2 are the first two entries. An interrupt is placed in the table by ‘irset(a,b,c)’ where:

  • (a) is the interrupt register that contains the flag that is set when an interrupt occurs. In the timer example, for this processor it will be either IFS0 or IFS1, you will need to consult the data sheet to find out which one to use.
  • (b) This is a mask that will result in a none zero value if the interrupt flag is set. In the timer example above this would be IFS0,0×4000 because bit 14 (0×4000) is the Timer 3 flag.
  • (c) This is a function that will be called to service the interrupt. This can be any function you create (must not have parameters or a return value) and it is the function name in text.

ByPic will take care of resetting the flag after the interrupt is called so you don’t need to.

As seen in the timer section, the timer will set a flag when it matches PR. We can use this now to test the interrupt.

http://byvac.com/mBlib/flb/Tutorial/PIC32MX1_Family/20_Interrupts/Project_1.bas

// Interrupt projects
//
#option echo off
#option only on   // only load functions that don't already exists

// include all of the registers although only some are needed
#include "http://byvac.com/mBlib/flb/Library/PIC32MX1_Family/BRegisters/MX1_reg_timer.bas"
// interrupts hold the flag addresses
#include "http://byvac.com/mBlib/flb/Library/PIC32MX1_Family/BRegisters/MX1_reg_interrupt.bas"

constant TIMERON 1 << 15 // on bit
constant T3IF 1 << 14

// *****************************************************************************
// clocked with PCLK that is running at 40MHz, prescale 256 = 156.25kHz (6.4uS)
// setting PR2 1/6.4uS = 156250 should see the counter reset every second so
// using 1562500 is 10 seconds.
// This also sets the interrupt
// *****************************************************************************
function t23_setir()
	// set timer to trigger every 10 seconds
	@TMR2=0  // clear counter
	// timer_on | prescale_256 | 32_bit_on | Internal_clock
	@T2CON = 0x8078
	@PR2=1562500
	// Set interrupts
	@IFS0CLR = T3IF  // clear interrupt
	@IPC3SET = (3 << 2)
	@IEC0SET = T3IF
endf

function t23_irq()
	print "\nI have been called"
endf

// just to look at timer values
function t23_test()
	t23_setir()
	irset(IFS0,T3IF,"t23_irq")
endf

Load this project and type t23_test. Nothing will happen at first but after 10 seconds a message will appear. Notice that this is a background task, you can still get the ok prompt.

The timer set up function is almost the same as before (in the timer projects) but these lines have been added:

@IFS0CLR = T3IF // clear interrupt

@IPC3SET = (3 << 2)

@IEC0SET = T3IF

The first line simply makes sure that there was not an existing interrupt and so clears the flag. In the second line we set the interrupt priority to 3. It has to be set to something and the last line enables the interrupt for timer 2/3.

This may need some clarifying; T3IF is a constant whose value is (1 << 14). Type print hex$(1 << 14) at the command prompt and you will get 0×4000. This means that bit 14 is set to high, incidentally ~(1 << 14) will give 0xffffbfff which is the opposite, bit 14 is low but the rest are high.

Likewise (2 << 3) will set bits 3 and 2 high.

This is an extract from the data sheet, we are concerned with T3IP (timer 3 interrupt priority). This is bits 2,3 and 4 (quite often shown as 4:2) of the IPC3 register. We want to set the register to priority 3 and so we need to put the value 3 in those bits and so we get:

Bit         4 3 2 1 0
Value     0 1 1 x x

The ‘x’ means that we are not bothered about these bits and so if we use 0 then the binary value is 01100 which is hex 0xc. This is a long winded way of saying (2 << 3) is place 3, 2 bits up. You can just about see the IEC0 register in the picture and see that bit 14 is T3IE which we set on the last line.

http://byvac.com/mBlib/flb/Tutorial/PIC32MX1_Family/20_Interrupts/Project_2.bas

// Interrupt projects
// Interrupt on change example
//
#option echo off
#option only on   // only load functions that don't already exists

// Interrupts
#include "http://byvac.com/mBlib/flb/Library/PIC32MX1_Family/BRegisters_short/MX1_reg_interrupt.bas"
// Ports
#include "http://byvac.com/mBlib/flb/Library/PIC32MX1_Family/BRegisters_short/MX1_reg_ports.bas"

constant IOCRA0	1 << 13

// *****************************************************************************
// example for interrupt on change for RA0 (pin 2)
// *****************************************************************************
function ioc_init()
dim nowt
	@CNCONA = 1 << 15	// global enable IOC
	poke(CNENA+SET,1)	// RA0
	poke(CNPUA+SET,1)	// enable weak pull ups
	poke(TRISA+SET,1)	// make sure RA0 is input
	poke(ANSELA+CLR,1)	// disable ADC
	nowt = @PORTA  // clear read
	nowt = @IFS1  // and flag
endf

// *****************************************************************************
// example shows that there is an interrupt each time the value changes on RA0
// for high to low or form loaw to high. To use, because of the pull up in place
// simply connect a wire from RA0 and connect to ground. There will be a change
// wehn connecting to ground and a change when diconecting fromn ground
// *****************************************************************************
function go()
dim count=0, nowt
	ioc_init()
	while comkey?(2) = 0
		if (@IFS1 & IOCRA0) <> 0 then
			nowt = @PORTA // have to read port
			@IFS1 = 0
			count = count + 1
			print format$("\ncount=%d",count);
			wait(100) // switch debounce
			// whilst poking arround with the wire it will inevitably have
			// cause another interrupt, so clear it after the delay
			nowt = @PORTA // have to read port
			@IFS1 = 0
		endif
	wend
endf

This is an example of using interrupt on change. The example shows how to set up and use RA0 so that it will set the interrupt flag when a change on the pin occurs. The output causes a counter to increment.

http://byvac.com/mBlib/flb/Tutorial/PIC32MX1_Family/20_Interrupts/Project_3.bas

// Interrupt projects
// External interrupt
//
#option echo off
#option only on   // only load functions that don't already exists

// interrupts hold the flag addresses
#include "http://byvac.com/mBlib/flb/Library/PIC32MX1_Family/BRegisters_short/MX1_reg_interrupt.bas"
// port
constant TRISBSET        0xBF886118
constant CNPUBSET        0xBF886158
// hardware
//	pin		INT
//	16		INT0	(RB7)
//
constant INT0EP 1 // interrupt
constant INT0 1 << 3
constant INP 1 << 7

// *****************************************************************************
// clocked with PCLK that is running at 40MHz, prescale 256 = 156.25kHz (6.4uS)
// setting PR2 1/6.4uS = 156250 should see the counter reset every second so
// using 1562500 is 10 seconds.
// This also sets the interrupt
// *****************************************************************************
function ext0_init()
	poke(INTCON+CLR,INT0EP) // set for falling edge
	@TRISBSET = INP // set as i/p
	@CNPUBSET = INP // enable pull up
	poke(IPC0+SET, (3 << 26)) // priority 3
	poke(IFS0+CLR,INT0) // clear any pending
	poke(IEC0+SET,INT0) // enable
endf

function ext0_irq()
	print "\ninterrupt pin low"
endf

// see if it works
function ext0_test()
	ext0_init()
	irset(IFS0,INT0,"ext0_irq")
endf

This is the same example as in the tutorial but none of the 'rookie' functions are used. It uses RB7 and if doing the tutorial it will need to be temporarily disconnected from the display.