Here is the code that is working for me. I am sending three bytes to the slave. In this example 10, 20 and 30. The slave adds 1 and sends back 11, 21 and 31.
Here is a snipit of the master portion.
Here is the full slave. Pic18F2620 @ 20MhzCode:I2Caddress = $0A I2CWrite i2cdat,i2cclk,I2Caddress,[10,20,30],NoGo pauseus 5 i2cread i2cdat,i2cclk,i2caddress,[tp_x, tp_y, tp_dp],NoGo2 pauseus 5 USBBuffer[0] = tp_x USBBuffer[1] = tp_y USBBuffer[2] = tp_dp USBBuffer[3] = 0 gosub dousbout ' I am using USB as a debugger pause 100 goto mainmenu NoGo: USBBuffer[0] = 1 USBBuffer[1] = 2 USBBuffer[2] = 3 USBBuffer[3] = 0 gosub dousbout goto mainmenu NoGo2: USBBuffer[0] = 4 USBBuffer[1] = 5 USBBuffer[2] = 6 USBBuffer[3] = 0 gosub dousbout goto mainmenu
Disregard all the extra stuff, I am using this slave a Touch Screen controller.Code:asm __CONFIG _CONFIG1H, _OSC_HS_1H __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_512_2H __CONFIG _CONFIG3H, _PBADEN_OFF_3H __CONFIG _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L endasm DEFINE OSC 20 'DEFINE ADC_BITS 10 'DEFINE ADC_CLOCK 3 'DEFINE ADC_SAMPLEUS 50 Define I2C_SLOW 1 DEFINE I2C_HOLD 1 'OSCCON = %01110001 '8mhz 'OSCTUNE.6 = 1 ' PLL selected 32mhz clock ' PicBasic Pro I2C slave program ' Alias pins scl VAR PORTC.3 ' I2C clock input sda VAR PORTC.4 ' I2C data input 'ADCON2.7=1 ADCON1 = $F '$B 'an1-an3 analog remainder digital CMCON = 7 'PortA Digital ' '---------------- Alias pins ----------------------------------- 'SCLDIR var TRISC.3 'SDADIR var TRISC.4 '--------------- Define used register flags ------------------- SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 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 STAT_BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full STAT_RW VAR SSPSTAT.2 ' SSP (I2C) Read/Write STAT_DA VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKE VAR SSPSTAT.6 ' SSP (I2C) Data/Address WrData var byte j var byte '------------------- Rx Buffer defintion -------------------- RxBufferLEN con 3 RxBuffer var byte[Rxbufferlen] RxBufferIndex var byte RxCnt var byte rxcnt = 0 '------------------ Tx Buffer defintion ---------------------- TxBufferLEN con 3 TxBuffer var byte[txbufferlen] TxBufferIndex var byte TxCnt var byte txcnt = 0 '------------------ Define constants ------------------------ rxinptr var byte rxoutptr var byte txinptr var byte txoutptr var byte rxinptr = 0 rxoutptr = 0 txinptr = 0 txoutptr = 0 I2Caddress CON $0A ' Make address = 2 ' Allocate RAM result VAR BYTE ' ADC result DataIn VAR BYTE[8] ' Data in DataOut VAR BYTE[8] ' Data out array readcnt VAR BYTE ' I2C read count readcnt = 0 ' Zero counter '**************************************************************** ' Variables used in the program. ' '**************************************************************** transdata var byte transbit7 var transdata.7 Tdata var word txdata var word tydata var word txcomp var word tycomp var word tx var word ty var word tvalue var word txcomp=0 tycomp=0 tx=0 ty=0 tvalue=0 PD var bit 'pen down flag address var byte ' -------------- Initialize I2C slave mode ------------------------ 'SCLDIR = 1 ' SCL must be an input before enabling interrupts 'SDADIR = 1 SSPADD = I2Caddress ' Set our address SSPCON1 = $36 ' Set to I2C slave with 7-bit address SSPCON2.0 = 1 SSPSTAT = 0 SSPIE = 1 SSPIF = 0 RxBufferIndex = 0 TxBufferIndex = 0 'LED1 var PORTC.1 ' Interrupt definition ' ==================== ' USB interrupt used to keep USB connection alive INCLUDE "DT_INTS-18.bas" ' Base Interrupt System INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler SSP_INT, _I2C_Int, PBP, yes endm INT_CREATE ; Creates the interrupt processor endasm ''----------------- Initialization Done! ----------------------------- @ INT_ENABLE SSP_INT ; Master Synchronous Serial Port Interrupt Flag bit. The transmission/reception is complete txbuffer = 0 portc.1 = 1'high led1 goto Main '***************************************************************************** '------------------------- I2C subroutine -------------------------------- I2C_Int: If R_W = 0 then 'Write from master if D_A = 0 then ' It's address from master address = SSPBUF ' do nothing rxcnt = 1 rxinptr = 0 rxoutptr = 0 txinptr = 0 txoutptr = 0 else WCOL = 0 sspov = 0 if bf = 1 then 'There is data in buffer if rxcnt < rxbufferlen then rxbuffer[rxinptr] = SSPBUF rxinptr = rxinptr + 1 if rxinptr = rxbufferlen then rxinptr = 0 endif rxcnt = rxcnt + 1 EndIF endif else ' Read by master dataout = SSPBUF 'dummy read if bf = 0 then ' if buffer is empty if txcnt > 0 then ' Is there a byte to transfer SSPBUF = txbuffer[txoutptr] 'get the byte abd send it txoutptr = txoutptr + 1 if txoutptr = txbufferlen then txoutptr = 0 txcnt = txcnt - 1 else 'no byte to send endif endif endif sspif = 0 CKP = 1 @ INT_RETURN ' -------------------------end I2C subroutine -------------------------------- '--------------------[ main program loop]--------------------------------------- Main: 'SSPOV = 0 'WCOL = 0 'INTCON.7 = 0 'trrn off interrupt if txcnt < txbufferlen then TxBuffer[txinptr] = rxbuffer[txinptr] | %00000001 ' add "1" to the data in txinptr = txinptr + 1 if txinptr = txbufferlen then txinptr = 0 txcnt = txcnt + 1 'INTCON.7 = 1 'turn on interrupt endif if rxcnt != 0 then datain = rxbuffer[rxoutptr] rxoutptr = rxoutptr + 1 if rxoutptr = rxbufferlen then rxoutptr = 0 endif rxcnt = rxcnt - 1 endif WrData=0 goto main end
Thanks
Dave
Group,
I'm back using the 18F4685, one in Master and one in Slave. I'm now able to read from the Slave, 3 digits (and their even the right ones!). I set up a fast loop to read the digits on the Master side and do nothing but send the data in a fast loop on the Slave side. (Will post both sides soon).
The problem is still the same on sending data from the Master to the Slave. The address gets there, matches, sets the SSPIF and BF, but also I get the SSPOV (overflow) bit set. Even on the first attempt to read the buffer, the OV is already set. There must be some "slow it down" handshaking not happening just right. Has anyone had luck sending multiple bytes to the Slave?
rswain
The attachments are the latest code (starting to work on the 18F4685). Still not able to send Master to Slave - Slave gets OVERFLOW flag.
Rswain
Last edited by rswain; - 15th March 2009 at 05:57.
You don't empty the SSPBUF after receiving the adress and the first data-byte gives you an buffer-overrun.....
PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2
BigWumpus,
You're right. I wasn't getting the bytes out of the Buffer fast enough. I tried a few things to empty the buffer faster and that helped. Now I don't have an Overflow problem, but I've managed to screw up the result that goes back to the Master when it asks for data from the Slave. I've got to go back double check the emptying and filling of the buffer.
I'm going to go back a step and make sure I've got the Master pulling data from the Slave perfectly. I'll take it up to 20 bytes or so to make sure. Once that's done, then I'll work again on sending data from the Master to the Slave. When I quit yesterday, I had it receiving two bytes (three if you count the address byte).
We're getting very close. I'll post working code as I accomplish these tasks.
Rswain
-------------------------deleted-------------------------
Last edited by BigWumpus; - 16th March 2009 at 17:10. Reason: CODE-code is messy
PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2
Try this:
I2C_Slave: ' I2C slave subroutine
IF R_W Then
I2C_Read: ' I2C read data from us ' THIS SECTION IS WORKING!
IF !d_a Then txbufferindex = 0
Repeat
Repeat
Until !bf
wcol = 0:sspbuf = txbuffer[txbufferindex]
Until !wcol
txbufferindex = txbufferindex + 1 ' increment index
IF txbufferindex = txbufferlen Then txbufferindex = 0 ' all bytes have been tx reset index
Else
IF !D_A Then
InByte=SSPBUF 'here is your error ! You don't empty the buffer!!!!!!!!!!!!!!!!!!!!!!
else
I2C_Write: ' I2C write data to us ' THIS SECTION NOT WORKING
If BF Then
InByte = SSPBUF ' Put buffer data into array
if rxbufferindex<rxbufferlen then Rxbuffer[Rxbufferindex] = InByte:rxbufferindex = rxbufferindex + 1
ENDIF
SSPov = 0 ' Clear overflow flag
endif
endif
ckp = 1 ' release clock, allowing read by master (makes no difference (yet))
SSPIF=0
The CODE-code is messy
PBP 2.50C, MCS+ 3.0.0.5, MPLAB 8, MPASM 5.14, ASIX Presto, PoScope, mE mikroBasic V7.2, PICKIT2
Hi, I'm interested to try the master-slave(I2C) worked by Daniel and other members, sorry if it is not obvious for me in the code given, but can someone share the schematic used in the example?
I'm using Pic16877(master) and Pic16F88(salve).
Thanks,
tacbanon
Last edited by tacbanon; - 24th April 2012 at 09:37.
From the code provided, here is how I interpret the pin connection between pics.
Master(Pic16F877A) Slave(Pic16F88)
(SCL)RB5 <---> RB4
(SDA)RB7 <---> RB1
but with this connection, LCD displays "Time out", can anyone help me what I'm missing?
Did you pullup SCL and SDA with a 3.3K resistor?
Cheers
Al.
All progress began with an idea
Hi aratti,
Thanks for replying, I added the resistors but I have the same output("Time out" on the lcd). Any idea what causing the issue?
Thanks in advance,
tacbanon
Attachment 6422
Last edited by tacbanon; - 25th April 2012 at 07:13.
You should post the schematic of your setup along with the code you are using. Without more info it is difficult to give you proper answers.
Al.
All progress began with an idea
Hi again,
Here is the code I'm using..
Master pic using Pic16F877A
Here is the code for the Slave Pic16F88Code:'------------------------------------------------------------------------------- ' Master '------------------------------------------------------------------------------- '------------------------------------------------------------------------------- DEFINE OSC 4 'OPTION_REG.7 = 0 ADCON1 = 7 '------------------------------------------------------------------------------ DEFINE I2C_SLOW 1 TRISB.5 = 1 TRISB.7 = 1 '------------------------------------------------------------------------------ scl VAR PORTB.5 ' i2c clock input sda VAR PORTB.7 ' i2c data input '------------------------------------------------------------------------------ I2Caddress VAR BYTE valor VAR BYTE '------------------------------------------------------------------------------ ' Set LCD Data port DEFINE LCD_DREG PORTD ' Set starting Data BIT (0 OR 4) IF 4-BIT bus DEFINE LCD_DBIT 4 ' Set LCD Register Select port DEFINE LCD_RSREG PORTC ' Set LCD Register Select BIT DEFINE LCD_RSBIT 6 ' Set LCD Enable port DEFINE LCD_EREG PORTC ' Set LCD Enable BIT DEFINE LCD_EBIT 7 ' Set LCD bus size (4 OR 8 bits) DEFINE LCD_BITS 4 ' Set number of lines ON LCD DEFINE LCD_LINES 2 ' Set command delay time in us DEFINE LCD_COMMANDUS 2000 ' Set Data delay time in us DEFINE LCD_DATAUS 50 '------------------------------------------------------------------------------ Pause 500 ' Wait for LCD to startup LCDOut $fe, 1 LCDOut $fe, "Daniel" Pause 500 ' Wait for LCD to startup valor = 0 '------------------------------------------------------------------------------ main: I2Caddress = $3 LCDOut $fe, 1 LCDOut "Write 1 - LED ON" Pause 500 I2CWrite SDA, SCL, I2Caddress, [6], bogus ' Write offset to slave Pause 500 LCDOut $fe, 1 LCDOut "Write 1 - LED OFF" Pause 500 I2CWrite SDA, SCL, I2Caddress, [8], bogus ' Write to slave Pause 500 LCDOut $fe, 1 LCDOut "Reading 1..." Pause 500 I2CRead SDA, SCL, I2Caddress, [valor], bogus ' Read from slave LCDOut $fe, 1 LCDOut "Value1: ", DEC valor Pause 500 '-------- I2Caddress = $5 LCDOut $fe, 1 LCDOut "Write 2 - LED ON" Pause 500 I2CWrite SDA, SCL, I2Caddress, [4], bogus ' Write to slave Pause 500 LCDOut $fe, 1 LCDOut "Write 2 - LED OFF" Pause 500 I2CWrite SDA, SCL, I2Caddress, [10], bogus ' Write to slave Pause 500 LCDOut $fe, 1 LCDOut "Reading 2..." Pause 500 I2CRead SDA, SCL, I2Caddress, [valor], bogus ' Read from slave LCDOut $fe, 1 LCDOut "Value2: ", DEC valor Pause 500 '-------- GoTo main ' Do it forever '------------------------------------------------------------------------------- bogus: LCDOut $fe,1, "Time out" ' I2C command timed out Pause 500 GoTo main '------------------------------------------------------------------------------- End
The codes I'm using is from Daniel(copy and paste).Code:DEFINE OSC 8 OSCCON = 110001 '8mhz '------------------------------------------------------------------------------ CMCON = 7 ADCON1 = 0 ' Disable A/D converter ADCON0 = 0 ANSEL = 0 ' all analog pins to digital '--- tris port config here (don't use SCL & SDA pins other than I2C) ---------- DEFINE I2C_HOLD 1 TRISB.1 = 1 TRISB.4 = 1 '--- Alias pins --------------------------------------------------------------- SDADIR VAR TRISB.1 SCLDIR VAR TRISB.4 '--- Define here your variables and alias ------------------------------------- LEDT VAR PORTA.2 LEDL VAR PORTB.7 LEDM VAR PORTB.6 LEDR VAR PORTB.5 readcnt VAR BYTE datain VAR BYTE WrData VAR BYTE '--- Define used register flags ------------------------------------------------ SSPIF VAR PIR1.3 ' SSP (I2C) interrupt flag SSPIE VAR PIE1.3 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 SSPCON.4 ' SSP (I2C) SCK Release Control SSPEN VAR SSPCON.5 ' SSP (I2C) Enable SSPOV VAR SSPCON.6 ' SSP (I2C) Receive Overflow Indicator WCOL VAR SSPCON.7 ' SSP (I2C) Write Collision Detect STAT_BF VAR SSPSTAT.0 ' SSP (I2C) Buffer Full STAT_RW VAR SSPSTAT.2 ' SSP (I2C) Read/Write STAT_DA VAR SSPSTAT.5 ' SSP (I2C) Data/Address CKE VAR SSPSTAT.6 ' SSP (I2C) Data/Address '--- Rx Buffer defintion ------------------------------------------------------ RxBufferLEN CON 1 RxBuffer VAR BYTE[Rxbufferlen] RxBufferIndex VAR BYTE '--- Tx Buffer defintion ------------------------------------------------------ TxBufferLEN CON 1 TxBuffer VAR BYTE[txbufferlen] TxBufferIndex VAR BYTE '--- Define constants --------------------------------------------------------- I2Caddress CON $3 ' Make address = 3 '--- Initialize I2C slave mode ------------------------------------------------ SCLDIR = 1 ' SCL must be an input before enabling interrupts SDADIR = 1 SSPADD = I2Caddress ' Set our address SSPCON = $36 ' Set to I2C slave with 7-bit address SSPSTAT = 0 SSPIE = 1 SSPIF = 0 RxBufferIndex = 0 TxBufferIndex = 0 '--- Initialization Done! ----------------------------------------------------- GoTo main '--- I2C subroutine ---------------------------------------------------------- i2cslave: ' I2C slave subroutine SSPIF = 0 ' Clear interrupt flag IF R_W = 1 Then i2crd ' Read data from us IF BF = 0 Then i2cexit ' Nothing in buffer so exit IF D_A = 1 Then i2cwr ' Data for us (not address) IF SSPBUF != I2Caddress Then i2cexit ' Clear the address from the buffer readcnt = 0 ' Mark as first read GoTo i2cexit i2cwr: ' I2C write data to us datain = SSPBUF ' Put buffer data into array Rxbuffer[Rxbufferindex]=datain Rxbufferindex=rxbufferindex+1 IF rxbufferindex=RxBufferLEN Then ' end of buffer transfer WrData=1 rxbufferindex=0 EndIF GoTo i2cexit i2crd: ' I2C read data from us IF D_A = 0 Then TxBufferIndex = 0 EndIF While STAT_BF : Wend ' loop while buffer is full wcol = 0 ' clear collision flag SSPBUF = TxBuffer[TxBufferIndex] While wcol wcol = 0 SSPBUF = TxBuffer[TxBufferIndex] Wend CKP = 1 ' release clock, allowing read by master TxBufferIndex = TxBufferIndex + 1 ' increment index IF TxBufferIndex = TxBufferlen Then ' all bytes have been tx TxBufferIndex = 0 ' reset index EndIF i2cexit: Return '--- End I2C subroutine ------------------------------------------------------ Main: pause 100 txbuffer = 12 IF SSPIF = 1 Then GoSub i2cslave EndIF SSPOV = 0 WCOL = 0 Select Case RxBuffer[0] Case 6 High LEDT Case 8 Low LEDT End Select WrData=0 GoTo Main '------------------------------------------------------------------------------ End
BTW I'm using a simulator...
regards,
tacbanon
Last edited by tacbanon; - 25th April 2012 at 10:07.
Bookmarks