SSP_INT...... Master Synchronous Serial Port Interrupt
SSP_INT Uses PIR1,SSP1IF, PIE1,SSP1IE
INCLUDE "DT_INTS-18.bas" ' Thanks Darrel! INCLUDE "ReEnterPBP-18.bas" ' ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler SSP_INT, _I2C_Int, PBP, yes INT_Handler TMR0_INT, MainTimer, ASM, yes endm INT_CREATE ; Creates the interrupt processor endasm
Charles Linquist
Post of 12-Feb-2011
Here is a fairly full-featured interrupt-driven I2C slave. The master part is easy.
This slave relies on the work of many others, but I have added some bug fixes and extra features. For example, you can write
0xAA,0X55,0x00,**your new address here**,0x00
and you can change the address of the slave.
Like my other stuff, it ONLY works on 18F chips.
Code: ASM ifndef __18F2321 error "18F2321 not selected" endif ENDASM ASM movlw 0x62 ; %0110 0010 = 4 Mhz, internal osc block movwf OSCCON movlw 0x80 ; %1000 0000 = PLL disabled movwf OSCTUNE ENDASM DATA @0,$38 ; Default I2C address if not determined in HW DEFINE OSC 4 Define USE_LFSR 1 ;---------------- Alias the bits ------------------------------------ SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 ' Int Enable SSPUA VAR SSPSTAT.1 SSPS VAR SSPSTAT.3 SSPP VAR SSPSTAT.4 SSPSMP VAR SSPSTAT.7 BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full R_W VAR SSPSTAT.2 ' SSP (I2C) Read/Write D_A VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKP VAR SSPCON1.4 ' SSP (I2C) SCK Release Control SSPEN VAR SSPCON1.5 ' SSP (I2C) Enable SSPOV VAR SSPCON1.6 ' SSP (I2C) Receive Overflow Indicator WCOL VAR SSPCON1.7 ' SSP (I2C) Write Collision Detect MasterClock VAR WORD BANKA SYSTEM '------------------- Buffer defintion -------------------- RxBufferLEN con 10 RxBuffer var BYTE[Rxbufferlen + 1] TxBufferLEN CON 10 TXBuffer VAR BYTE[TxBufferLEN + 1] GeneralCall VAR BIT RXBufferOverFlow VAR BIT TxBufferUnderFlow VAR BIT HWAddress VAR BIT RXBufferPointer VAR Byte TXBufferPointer VAR Byte address VAR BYTE x VAR BYTE dummy var byte I2CAddress VAR BYTE WCOLCounter VAR BYTE I2CDeviceAddress VAR BYTE Holdoff VAR WORD ; retry timer HWAddress = 0 ; Get address from EEPROM, not pins TestArray VAR BYTE [200] IF !HWAddress THEN ;----------- Get our Address from EEPROM -------------- READ 0,I2CAddress ;----------------------------------------------------- ELSE ;----------------OR Get our address from PORT B0..2----------- I2CDeviceAddress = PORTB & %00000111 I2CMajorAddress CON $3 ; upper 4 bits I2CAddress = (I2CMajorAddress <<4) | I2CDeviceAddress <<1 ; bit 0 is R/W ;--------------------------------------------------------------- Endif SSPADD = I2Caddress ' Move our address into the proper reg SSPCON2.0 = 1 ; Allow clock stretching SSPCON2.1 = 0 ; Set to 1 to enable masking of address 1 ; 0 is R/W bit SSPCON2.2 = 0 ; Set to 1 to enable masking of address bit 2 SSPCON2.3 = 0 ; Set to 1 to enable masking of address bit 3 SSPCON2.4 = 0 ; Set to 1 to enable masking of address bit 4 SSPCON2.5 = 0 ; Set to 1 to enable masking of address bit 5 SSPCON2.6 = 0 ; Not used in slave SSPCON2.7 = 1 ; General Call enabled SSPSTAT = 0 SSPEN = 1 SSPIE = 1 SSPIF = 0 SSPCON1 = $36 ' Set to I2C slave with 7-bit address ;--------------------------------------------------------------- TRISA = %11111111 TRISB = %11111111 TRISC = %11111111 ' -------------- Turn on Ints ------------------------ INTCON.7 = 1 ; global ints INTCON.6 = 1 ; peripheral ints IPR1.3 = 1 ; high priority ;------------------ Clear parameters -------------- RXBufferPointer = 0 TxBufferPointer = 0 GeneralCall = 0 RxBufferOverFlow = 0 TXBufferUnderFlow = 0 WCOLCounter = 0 ;----------------Timer Setup----------------------------------- T0CON = %10000011 ; /16 prescaler ;-------- ------------------------------------------- WDTCON = 1 ; Turn on the WDT ;-------------------------------------------------------------- INCLUDE "DT_INTS-18.bas" ' Thanks Darrel! INCLUDE "ReEnterPBP-18.bas" ' ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler SSP_INT, _I2C_Int, PBP, yes INT_Handler TMR0_INT, MainTimer, ASM, yes endm INT_CREATE ; Creates the interrupt processor endasm ''----------------- Initialization Done! ----------------------------- Goto OverInt ; jump over ISR, don't execute it. ;----------------------- Timer INt ------------------------------------ ASM MainTimer movlw 0x00 ; 10 mSec movwf TMR0H movlw 0x63 movwf TMR0L infsnz MasterClock incf MasterClock + 1 ; This is a good place to pick up pin changes INT_ENABLE TMR0_INT INT_RETURN ENDASM ;--------------------------------------------------------------------- '------------------------- I2C subroutine -------------------------------- I2C_Int: ; We don't get here uless someone has matched our address register. If R_W = 0 then 'This is a WRITE by the master to us IF BF = 0 Then goto i2CEXIT ; Nothing for us! if D_A = 0 then 'We have an address address = SSPBUF 'Need to READ Address from buffer to clear it. IF Address = 0 THEN GeneralCall = 1 ; Set flag if we got a general call address ELSE GeneralCall = 0 ENDIF else IF WCOL OR SSPOV THEN I2CExit IF RXBufferPointer < RxBufferLen - 1 THEN RXBuffer [RxBufferPointer] = SSPBuf ; RxBufferPointer = RXBufferPointer + 1 ELSE Dummy = SSPBuf ; Grab the data but don't overwrite old RXBufferOverFlow = 1 ENDIF ENDIF else ' R_W = 1 Master wants to read FROM us IF !D_A Then TxBufferPointer = 0 ' Mark as first read RXBufferPointer = 0 EndIF IF CKP THEN I2CExit dummy = SSPBUF ;NECESSARY! SENDI2C: WCOL = 0 SSPBUF = TXBuffer[TXBufferPointer] ' Get data from array IF WCOL THEN WCOLCounter = WCOLCounter + 1 ; Don't hang the bus with infinite WRITES! IF WColCounter >= 7 Then goto I2CExit ; 7 RANDOM Holdoff Pauseus Holdoff >> 3 ; wait 0-8 msec Goto SendI2C ; Retry ELSE WColCounter = 0 ENDIF TXBufferPointer = TXBufferPointer + 1 If TXBufferPointer = TXBufferLen THEN TXBufferUnderflow = 1 TXBufferPointer = TXBufferLen - 1 ; Repeat last if req made again, but set flag now ENDIF ENDIF I2CEXIT: SSPOV = 0 BF = 0 sspif = 0 CKP = 1 @ INT_ENABLE SSP_INT ; probably don't need this, but I like to be certain it gets restarted @ INT_RETURN ' -------------------------end I2C subroutine -------------------------------- '--------------------[End ISRs]--------------------------------------- OverInt: @ INT_ENABLE SSP_INT @ INT_ENABLE TMR0_INT '--------------------[ main program loop]--------------------------------------- Main: IF RXBuffer[0] = $AA THEN IF RXBuffer[1] = $55 and RXBuffer[2] = 0 And RxBuffer[4] = 0 THEN Dummy = RXBuffer[3] WRITE 0,Dummy ; Write a new address Pause 10 @ RESET ; and pick up the new address ENDIF ENDIF ;------------------- Load the input buffer to the output buffer for test ----------- For X = 0 to TXBufferLen - 1 TxBuffer[X] = RXBuffer[X] next x ;---------------------------------------------------------------------- goto main end ASM ORG 0x0FF0 ; Keep track of pgm size in case we want to use it on a smaller chip NOP ENDASM
Page last modified on March 07, 2018, at 05:59 PM