|
|
View previous topic :: View next topic |
Author |
Message |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Feb 21, 2017 5:29 am |
|
|
This whole thread is running blind because you have not posted a test
program that shows the problem. It might be that we could look at your
i2c slave code and spot the problem right away. You also have not
posted your compiler version.
It should be possible to put together a minimalist test program that
shows your problem, and post it, along with your compiler version.
The program must have all #fuses, etc., and be compilable without errors. |
|
|
Futterama
Joined: 17 Oct 2005 Posts: 98
|
|
Posted: Tue Feb 21, 2017 2:03 pm |
|
|
Test program with compiler 5.042:
test.h
Code: | #include <12F1840.h>
#FUSES NOWRT // Program memory not write protected
#FUSES INTRC_IO // Internal RC Osc, no CLKOUT
#fuses NOWDT //No Watch Dog Timer
#fuses PUT //Power Up Timer
#fuses NOMCLR //Master Clear pin used for I/O
#fuses PROTECT //Code protected from reads
#fuses NOCPD //No EE protection
#fuses NOBROWNOUT //No brownout reset
#fuses NOCLKOUT //I/O function on OSC2
#fuses NOIESO //Internal External Switch Over mode disabled
#fuses NOFCMEN //Fail-safe clock monitor disabled
#fuses WRT //Program Memory Write Protected
#fuses NOSTVREN //Stack full/underflow will not cause reset
#fuses NODEBUG //No Debug mode for ICD
#fuses NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(internal=32MHz)
#use i2c(SLAVE, I2C1, ADDRESS=0x18, FORCE_HW)
#use fast_io(a) |
test.c
Code: | #include <test.h>
int8 I2C_bufferindex = 0;
int8 I2C_buffer[16] = {0x0C, 0x00, 1, 'T', 'e', 's', 't', ' ', 'I', '2', 'C', ' ', 'P', 'I', 'C', 0};
#INT_SSP
void SSP_isr(void)
{
int8 I2C_state, I2C_address;
I2C_state = i2c_isr_state(); // Get state
if(I2C_state == 0x80) // Address match with R/W bit set
{
I2C_address = i2c_read(2); // Read from I2C and don't release the clock
}
if(I2C_state > 0x7F) // Slave needs to write data
{
i2c_write(I2C_buffer[I2C_bufferindex]); // Write data
I2C_bufferindex++; // Increment buffer index
}
if(I2C_state == 0x90) // Last data byte has been written
{
I2C_bufferindex = 0; // Reset buffer index
}
}
void main()
{
set_tris_a(0b11101111);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(TRUE)
{
}
} |
Code: | Memory usage: ROM=4% RAM=11% - 18%
0 Errors, 0 Warnings.
Build Successful.
|
The master device starts by enumerating the bus and the PIC needs to answer back twice. If it does, the master device will poll it continuously after that. The data is 16 bytes and the text in the data is displayed on the master device system.
I checked my notes from the other forum, and what I found was that with the 10k pull-up master (Cypress MCU), things worked OK, but when I switched to the 1k1 pull-up master (STM MCU), things got bad. I can replicate this by adding 1k pull-ups when using the 10k pull-up master.
I have scope shots of the 10k pull-up master with no additional pull-ups and then with 1k pull-ups added (running 16MHz clock).
At 16MHz the PIC runs fine with the added 1k pull-ups and 3.3V VDD. At 32MHz, it will not reply to the masters enumeration with the 1k pull-ups, but if I remove those, is will answer. Unfortunately, I can't really remove them from the STM device which has the built-in 1k1 pull-ups.
Cypress 10k pull-up device with no additional pull-up:
http://drive.google.com/uc?export=view&id=0B-a5yG3Hqo3BZ2tTQnpueTZ4TVE
Cypress 10k pull-up device with additional 1k pull-up:
http://drive.google.com/uc?export=view&id=0B-a5yG3Hqo3BRWtIWC1Uc19PRjA |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9269 Location: Greensville,Ontario
|
|
Posted: Tue Feb 21, 2017 3:15 pm |
|
|
this...
At 16MHz the PIC runs fine with the added 1k pull-ups and 3.3V VDD
...seems to be a reasonable solution.
When I look at the 2 scope shots, the one without the 1k pullups is 'terrible'. Aside from the 'lazy' leading edge, there's some mysterious 'blips' on the data line....
Without having that PIC to play with, I don't know why it doesn't run at 32MHz for you properly. I would suggest using a 2nd PIC to emulate the 'device'. One huge problem is not knowing what really ' inside' that device and how it does work.There are 4 or 5 possible 'solutions' based on what's presented, which 'fits' best depends on your time and pocketbook.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19587
|
|
Posted: Wed Feb 22, 2017 2:16 am |
|
|
The waveforms with the 10K pull-ups are out of spec.
Problem #1.
Then the handling is 'short cutting' standard I2C. The standard for an I2C read transaction, is:
start
send write address
write register address
restart
send read address
read byte(s)
stop
Instead the transaction is assuming that the read address will reset itself.
Now if everything remains perfectly synchronised this is fair, but as done, will go out of sync if anything unexpected is seen on the bus. This is 'why' the bus has start and stop transactions and these should be used to synchronise the transaction. The glitches visible are extremely worrying, and may well trigger unexpected states...
Then there is a problem that as written, if the bus sees an unexpected 'start' that is not followed by an address match 'write start', the chip will become hung. Remember the chip will see _all_ start transactions on the bus. This is why it _must_ read the address byte that follows, whatever direction is selected.
Finally the code needs to reset the CKP. There is an issue that is particularly prone to happen when the processor is running fast, that the reset done immediately after a write, may not work. It's documented in about four chip errata, but actually seems to apply to all PIC's (I've reported it on about three where it was not a listed erratum...).
The address also needs to be static.
Then there is no attempt to handle the possible error states. With the glitches seen, these need to be handled...
As a general comment also, don't enable protection till _after_ you have finished debugging.
Doing so, wastes lives on the chip memory. With this disabled, and the programmer set to only erase as needed, only the parts of the code you change have to be erased. With protection enabled _every_ cell in the memory has to be erased, even to change just one byte. Result lives being used up....
So:
1) More pull-up needed.
2)
Code: |
#bit CKP=getenv("BIT:CKP")
#bit WCOL=getenv("BIT:WCOL")
#bit SSPOV=getenv("BIT:SSPOV")
#INT_SSP
void SSP_isr(void)
{
int8 I2C_state, dummy;
static int8 I2C_address; //must be static
//first handle possible errors
if (WCOL)
WCOL=FALSE; //write collision - should be impossible
if (SSPOV)
{
//overflow no read was done
dummy=I2C_read();
SSPOV=FALSE;
return; //break out, since byte will be bad.
}
I2C_state = i2c_isr_state(); // Get state
if (i2c_state<0x7F)
dummy=i2c__read(); //dummy read in unexpected state
if(I2C_state == 0x80) // Address match with R/W bit set
{
I2C_address = i2c_read(2);
// Read from I2C and don't release the clock
I2C_bufferindex = 0; // Use this to reset buffer index 'in case'
}
if(I2C_state > 0x7F) // Slave needs to write data
{
i2c_write(I2C_buffer[I2C_bufferindex]); // Write data
I2C_bufferindex++; // Increment buffer index
//Now need to ensure clock releases
CKP=TRUE;
}
if(I2C_state == 0x90) // Last data byte has been written
{
I2C_bufferindex = 0; // Reset buffer index
}
}
|
This should handle all potential bus states.
I suspect that with the increase in sampling frequency when the clock goes faster, the PIC is seeing some of the glitches as legitimate states, and possibly entering the ISR in perhaps state 0. This is then not reading the buffer, which will then result in SSPOV being set, and the peripheral becoming hung.... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|