|
|
View previous topic :: View next topic |
Author |
Message |
FloDu
Joined: 18 Sep 2024 Posts: 5
|
i2c_transfer_in() stucks in read out loop |
Posted: Wed Sep 18, 2024 6:24 am |
|
|
Hey guys,
I'm trying to write and read data over I2C FORCE_HW on a PIC18F27Q43 and the CCS 5v115. The code is running perfectly using the FORCE_SW directive with the i2c_start, i2c_write, i2c_read, i2c_stop functions. The GPIOs are the C3 and C4 (which are the HW I2C pins on my controller).
Now I added a new device to the I2C bus which requires me to use the hardware I2C. Using the FORCE_HW directive forces me to use the i2c_transfer (_in/_out) function. There is no problem writing data to the bus using the i2c_transfer_out funtion, but if I want to read data from the device using i2c_transfer_in, I got stuck in a read out loop.
I want to read out a single byte of the I2C slave. The controller starts the read out by sending the address, the slave sends an ACK and its data. Afterwards the controller keeps reading out the slave until the slave pulls down the SDL line.
What is happening here? Is there something wrong with my code? Or is there a known bug with the i2c_transfere_in function?
My code is the following:
Code: |
static uint8_t WriteData = NEXTCMD(ST_CB_INST);
static uint8_t ReadData[2];
i2c_transfer_out(RD(ST_ADDRESS), &WriteData, 1);
delay_us(100);
i2c_transfer_in(RD(ST_ADDRESS), &ReadData, 2);
|
Thank you very much for you help and hints.
Greeting
FloDu[/code]
Last edited by FloDu on Wed Sep 18, 2024 8:06 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19529
|
|
Posted: Wed Sep 18, 2024 7:37 am |
|
|
What compiler version do you have?.
When I2C_transfer_in was originally written it required the number of
bytes to be the total number of bytes in the transaction.
This was changed a while ago, so it is now the number of bytes to read.
The manual was changed to reflect this. |
|
|
FloDu
Joined: 18 Sep 2024 Posts: 5
|
|
Posted: Wed Sep 18, 2024 8:10 am |
|
|
Hey, thanks for oyu reply. Sorry for the missing information. I use the compiler V5.115.
I tried both variants of length, the payload length + one byte for the address and only the payload length. It's the same result in both cases.
Greetings
FloDu |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19529
|
|
Posted: Wed Sep 18, 2024 9:14 am |
|
|
I'm wondering if the driver is setting the ACNT bit in the peripheral.
This autoloads the byte count with the first byte received after the read
is started. Designed for devices that reply with the number of bytes
they are sending at the start of the read. If the ACNT bit is set this is
done. This ability doesn't exist in most of the I2C peripherals, but your
one has this. The driver may have missed this and left it set.
Might be worth trying clearing this yourself. |
|
|
FloDu
Joined: 18 Sep 2024 Posts: 5
|
|
Posted: Mon Sep 23, 2024 6:25 am |
|
|
Hey,
I created a new project which only reads in data over i2c. Using the FORCE_SW it is still working. But if I change to FORCE_HW, I see the same behaviour as in my production project.
The big advantage in the new project is a nice and clean list file, which makes it easy to follow the asm code. And there is something confusing:
Code: | ! i2c_transfer_out(RD(ST_ADDRESS), &WriteData, 1);
0xAE: MOVLB 0x2
0xB0: BCF SPI2BAUD, 4, BANKED
0xB2: MOVLW 0x1
0xB4: MOVWF SPI2RXB, BANKED
0xB6: MOVLW 0x7C
0xB8: MOVWF SPI2TCNT, BANKED
0xBA: CLRF 0x8, ACCESS
0xBC: MOVLW 0x5
0xBE: MOVWF 0xA, ACCESS
0xC0: MOVLW 0x4
0xC2: MOVWF 0x9, ACCESS
0xC4: MOVLB 0x0
0xC6: BRA I2C_TRANSFER_OUT_HW_3190
! delay_us(100);
0xC8: CLRWDT
0xCA: MOVLW 0x10
0xCC: MOVWF 0x0, ACCESS
0xCE: DECFSZ 0x0, F, ACCESS
0xD0: BRA 0xCE
! i2c_transfer_in(RD(ST_ADDRESS), &ReadData, 2);
0xD2: MOVLB 0x2
0xD4: BCF SPI2BAUD, 4, BANKED
0xD6: MOVLW 0x7D
0xD8: MOVWF SPI2TCNT, BANKED
0xDA: MOVLW 0x2
0xDC: MOVWF SPI2RXB, BANKED
0xDE: CLRF 0x8, ACCESS
0xE0: MOVLW 0x5
0xE2: MOVWF 0xA, ACCESS
0xE4: MOVWF 0x9, ACCESS
0xE6: MOVLB 0x0
0xE8: BRA I2C_TRANSFER_IN_HW_3190 |
Why is there an access to the SFRs of the SPI2 peripheral before calling the I2C_TRANSFER functions?
On the old PIC controllers (K22) there is the MSSP, where the I2C bus is part of the MSSP module, but the Q43 has a dedicated I2C module.
On the Q43 controller I would expect writing the I2C1CNT register.
Is this a bug in the compilers functions for my Q43 controller? Who can help me with this question?
Thanks you _________________ --------------------
Greetings
FloDu
I'm using CCS V5.115 on a PIC18FXXQ43 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19529
|
|
Posted: Mon Sep 23, 2024 7:45 am |
|
|
There's not!....
It puzzled me too, but if you look the addresses it accesses is the correct
addresses for the I2C registers.
The name being used is wrong. Historically of course I2C was handled
by the MSSP peripheral, which did both I2C and SPI. looks as if whoever
coded this still hasn't got their head around the peripherals being separate
on these chips.
However I walked through the code and it is accessing the I2C registers
not the SPI registers.
Switch the compiler so it doesn't use the symbolic notation and look at
the actual addresses being used. A pain I know, but it does look right.
I can confirm it does still just transfer the 'count' value directly into the
chip register.
Try being sneaky and use i2C_transfer, rather than i2c_transfer_in.
So:
i2c_trasnfer(RD(ST_ADDRESS), NULL, 0, &ReadData, 2);
You have not answered about what RD(ST_ADDRESS) actually is?.
Have you tried what happens if you use i2c_read and i2c_write with the
hardware, rather than i2C_transfer?.
Historically this didn't work on chips with the I2C peripheral, but I know
on some other chips CCS does now allow these to be used.
I think the fact the address naming is wrong says you really ought to
talk to CCS about this. It is a fault and should be fixed, and they will
know if anything else is wrong.
However I have to ask why you say you 'have to use hardware'?. The
only advantage of hardware over software is it allows faster I2C speeds
when you are clocking the processor slowly, and it supports use as a slave,
which the software can't do. |
|
|
FloDu
Joined: 18 Sep 2024 Posts: 5
|
|
Posted: Mon Sep 23, 2024 9:39 am |
|
|
Hey Ttelmah,
I double checked this and figured out that the correct registers are accessed. I was confused by the alias, but the BSR is loaded with 2, so the correct registers are accessed.
As I dived deep in the code and the CCS functions (assembler code) I figured out that the transfer_in function is waiting for the I2CSTAT0->MMA Bit is cleared, which is not cleared by the hardware and the code hangs up between the line 0094 and 009C. The MMA bit should be cleared when a stop condition is issued, which should happen after the I2CCNT reaches zero and a NACK is sent to the bus by the mastern.
In my case there is no NACK on the bus.
I have no idea why this is happening, but I will try to figure this out by writing my own transfer_in function based on the CCS's function. Below is the assembler code of the transfer_in function.
Code: |
00066: MOVLB 2
00068: BCF x97.4
0006A: BCF x99.3
0006C: BSF x99.2
0006E: BCF x95.6
00070: BSF x95.7
00072: MOVFF 50A,4EA
00076: MOVFF 509,4E9
0007A: BSF x94.5
0007C: BTFSC x94.5
0007E: BRA 007C
00080: BCF x94.6
00082: BTFSC x97.4
00084: BRA 0094
00086: BTFSS x99.0
00088: BRA 0082
0008A: MOVFF 28B,4EE
0008E: MOVF x8D,W
00090: BZ 0094
00092: BRA 0082
00094: BTFSC x99.0
00096: MOVFF 28B,4EE
0009A: BTFSC x98.5
0009C: BRA 0094
0009E: CLRF 501
000A0: BTFSC x98.3
000A2: BRA 00A8
000A4: BTFSC x97.4
000A6: INCF 501,F
000A8: MOVLB 0
000AA: GOTO 00EA (RETURN)
|
To answer you questions:
- the i2c_transfer function is also not working as it should
- RD(ST_ADDRESS) is the slave address 0x3E
- The i2c_read and _write functions are not available when using FORCE_HW.
- I am using a graphical display with 160*120 pixels (4 pixel per byte results in 4800 byte). To reduce the CPU load I want to write the display using HW I2C and DMA. I've already written the driver using the XC8 compiler and it's working very smooth. Now I have to port it, because the production firmware is using the CCS. _________________ --------------------
Greetings
FloDu
I'm using CCS V5.115 on a PIC18FXXQ43 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19529
|
|
Posted: Mon Sep 23, 2024 10:49 am |
|
|
That makes sense. As you say the master is meant to send the NACK
when the count reaches zero. I repeat to talk to CCS. On things like
this they are very good, and may know what is going wrong.
DMA makes sense.
I'm very surprised the device allows a read like this. Normally on I2C,
you have to send the register to be accessed to the device before you
can do a read or write. So the normal transfer is:
START
device address(W)
register address
data to write.
STOP
Or for a read:
START
device address(W)
register address
RESTART
device address(R)
read data
STOP
Are you sure your device correctly handles the write/read without a
register address?.
Not having this could be leaving the device not able to handle this. |
|
|
FloDu
Joined: 18 Sep 2024 Posts: 5
|
|
Posted: Tue Sep 24, 2024 12:26 am |
|
|
Hi,
of course I'm writing the register before reading data from the device (see my code listing in the first post). However the master should stop the read transaction after the given count of bytes.
Just to understand you correctly, should I get in contact with the CCS guys? Or are you part of the CCS team and can get more information about this behaviour?
Thank you for your help so far _________________ --------------------
Greetings
FloDu
I'm using CCS V5.115 on a PIC18FXXQ43 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19529
|
|
Posted: Tue Sep 24, 2024 3:09 am |
|
|
I think you are misunderstanding about addresses.
Your post does not show a register address being written. Or is this
what you send in your write?. If so, this is wrong. You should not stop
between sending the address and switching to reading.
Code: |
static uint8_t WriteData = NEXTCMD(ST_CB_INST);
static uint8_t ReadData[2];
i2c_transfer(RD(ST_ADDRESS), &WriteData, 1, &ReadData, 2);
|
Normally there should not be a stop between sending the register address
and starting the read. There should be a restart. Some devices will accept
a stop, but a lot won't. They set their pointers back to zero when a STOP
is seen. This is why the combined command is there.
Yes. If you look at the header of the forum, it tells you CCS does not
monitor this forum on a regular basis. Given there is a definate issue
with at least the register names, you need to be talking to them. |
|
|
|
|
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
|