View previous topic :: View next topic |
Author |
Message |
frank_the_programmer
Joined: 05 Feb 2024 Posts: 7
|
I2C slave no ACK bit help. |
Posted: Mon Feb 05, 2024 2:28 pm |
|
|
This is my first CCS project and I'm running into some problems implementing a dsPIC33FJ128GP204 as an I2C slave device. I hooked up an Arduino to act as the master for testing purposes. Everything seems to be correct except I can't get past the acknowledgment bit. I hooked up my O-scope to the data lines and I can see the correct address. The PIC also fires off the interruption, but It won't pull down the ACK bit to continue the data transmission.
As far as software goes I've copied over and slightly modified one of the examples called ex_slave.c. I attempt to print out the buffer, but it's all zeros.
Code: | // #include <main.h>
#include <33FJ128GP204.h>
#include <stdint.h>
#include <stdbool.h>
#define RX_PIN PIN_C6
#define TX_PIN PIN_C7
#device ICSP = 1
#use delay(internal = 20000000)
#fuses NOWDT // No Watch Dog Timer
#fuses CKSFSM // Clock Switching is enabled, fail Safe clock monitor is enabled
// setup the uart
#use rs232(UART1, baud = 115200, XMIT = TX_PIN, RCV = RX_PIN, stream = UART_PORT1, ERRORS)
#use i2c(SLAVE, I2C1, FORCE_HW, ADDRESS = 0x10)
uint8_t address, buffer[16] = {0};
uint8_t incoming = 0;
bool rec = FALSE;
#INT_SI2C
void i2c_interrupt(void)
{
uint8_t state;
state = i2c_isr_state();
if (state <= 0x80) // Master is sending data
{
if (state == 0x80)
incoming = i2c_read(2); // Passing 2 as parameter, causes the function to read the SSPBUF without releasing the clock
else
incoming = i2c_read();
if (state == 1) // First received byte is address
address = incoming;
else if (state >= 2 && state != 0x80) // Received byte is data
buffer[address++] = incoming;
}
if (state >= 0x80) // Master is requesting data
{
i2c_write_slave(buffer[address++]);
}
rec = TRUE;
}
void main()
{
// wait for uart to setup
delay_ms(1000);
// setup interrupts
enable_interrupts(INTR_GLOBAL);
enable_interrupts(INT_SI2C);
// forever loop
while (TRUE)
{
// check i2c
if (rec == TRUE)
{
for (int i = 0; i < 16; i++)
{
printf("buf %u) %u\r\n", i, buffer[i]);
}
rec = FALSE;
}
}
}
|
Does anyone know what I could be doing wrong? If it's not the software I think it might be a hardware issue (on my part) Thank you! |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Mon Feb 05, 2024 4:20 pm |
|
|
what is VDD ?
what are I2C pullups ? |
|
|
frank_the_programmer
Joined: 05 Feb 2024 Posts: 7
|
|
Posted: Mon Feb 05, 2024 6:52 pm |
|
|
3V for VDD and two 3V pull-ups on both lines. Do I have to enable the ack in the software? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Tue Feb 06, 2024 7:39 am |
|
|
The buffer will be zeros, since the data has not yet been received. You are
setting the 'rec' flag every time the code leaves the interrupt. So in the
read of the address byte, etc... You need to wait till the count gets to 16
bytes received before setting this.
What are you pull up resistors?.
How fast are you driving the bus?.
As I read it, you are trying to receive 16bytes?.
There is an issue with your address. In I2C 7bit addresses under 0x10
are 'reserved'. Now the PIC uses an 8bit address. So if your Arduino is
talking to it's address 0x10, the PIC needs to be set to use 0x20. |
|
|
frank_the_programmer
Joined: 05 Feb 2024 Posts: 7
|
|
Posted: Sun Feb 18, 2024 11:43 pm |
|
|
Thank you for the reply, but I'm still encountering issues with the I2C. I was aware of the 8-bit address as I found out the hard way, but the issue still remains. Even though the I2c interrupt fires off, I can get the PIC (slave) to turn off the ACK bit. Since then I've switched over to an STM32 and I have the same situation. I'm using 10k Pullup resistors on the PIC side and nothing is set on the SMT32 side. Both are 3.3v devices and use 100khz (slow) speed.
I've simplified the problem below as the STM32 attempts to send 2 bytes and I can see the PIC fire off the interrupt. I can scope the correct address and the R/W bit is low for writing from the master. For some reason, the ACK bit never seems to be pulled down which I assume ends the transmission. The STM32 also will print a timeout error. The code below should help demonstrate the issue because when running this the state never changes from 0. Maybe I'm doing something wrong.
Code: |
#use i2c(SLAVE, SLOW, I2C1, FORCE_HW, ADDRESS=0x20)
#INT_SI2C
void i2c_interrupt(void)
{
uint8_t state;
state = i2c_isr_state();
i2c_read();
printf("%u\r\n",state);
} |
If anyone knows of any troubleshooting ideas I'd appreciate it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Mon Feb 19, 2024 2:21 am |
|
|
OK.
First thing, 10K is too large. On 5v 12C, with a reasonably short bus, 4K7
is OK, but on 3.3v 3K is the equivalent value. So reduce this.
Then the printf, will cause problems. It could be sending up to 5 bytes.
You don't say what your baud rate is, but the routine needs to exit in
a few uSec. The hardware buffering is not enough for such a long message.
Then are you sure about your address???. Is the STM talking to address
0x10?. It needs to be. Remember the PIC uses 8bit addressing. Most
devices use 7bit addressing. A NACK after the address byte means no
slave is responding.
You don't need to specify a 'speed' in the slave device. |
|
|
frank_the_programmer
Joined: 05 Feb 2024 Posts: 7
|
|
Posted: Mon Mar 11, 2024 2:30 pm |
|
|
I've reduced the resistors to 4.7k and removed the print function. I still get the interrupt but no ACK bit :(
I'm certain about the address as I've run a bus scanner to test what addresses respond, but no luck. Not sure what to do from here.
[img]https://forum.microchip.com/servlet/rtaImage?eid=a58V40000005fP7&feoid=00N3l00000FRqlI&refid=0EMV4000000Y56v[/img] |
|
|
frank_the_programmer
Joined: 05 Feb 2024 Posts: 7
|
|
Posted: Tue Mar 12, 2024 1:47 pm |
|
|
I GOT IT! Turns out I was testing on some damanged hardware. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Tue Mar 12, 2024 2:34 pm |
|
|
Happens to us all. Glad you have it sorted. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Mar 12, 2024 7:53 pm |
|
|
Yes, I got nailed for months when 'they' decided to reverse the usage of pins 2 and 3 when 'RS-232- connectors went from 25 pin to 9 pin.
I'd love to know WHO changed it and WHY !!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Wed Mar 13, 2024 7:56 am |
|
|
They didn't!......
If you look the standard connector on the 25pin serial on a PC, was the
DB-25F. The 9 pin serial is a DE-9M. The switch of size was also a switch
in gender, and implicitly there was also a swap on the assumption of
whether a PC was going to be a DCE or a DTE device. DCE and DTE devices
have the use of the two pins swapped.
The smaller connector was setup on the assumption the PC would not
be a 'terminal' any more.
Also designed to confuse.... |
|
|
|