2
\$\begingroup\$

I am struggling to get multiple read from the RHR register working on my SC16IS750 breakout board. I am using the board with I2C standard frequency, normal single reads and write are working fine.
The chip has a FiFo which can hold up to 64 characters. The Fig 24 in the Chip Manual (http://www.nxp.com/documents/data_sheet/SC16IS740_750_760.pdf) shows how multiple read should work. However when initiating such a multiple read only the first character is correctly transfered. All other characters are "0". If eg the FiFO held 16 characters before the transfer it will be empty afterwards. It seems that the chip recognize a multiple read but does not transfer the value on the bus.
Here what I do when receiving a FiFO Interrupt from the Chip:
- Read interrupt status register IIR
- Read Line Status register LSR
- Read RX Level register RXLVL - ie number of Charcaters in Fifo
- Read Multiple data:

I2C start,
slave address+write,
register address,
repeated start,
slave address+read,
RXLVL-1 time do (read character, ACK)
on last character (read, NACK)

I'll send a test pattern to the chip with 16 characters, only the first character is correct the rest are "0". RXLVL shows 16 before read. Does anybody know what needs to be setup/considered for this operation with the NXP chip?

Addtions:
a) I read the following contents out of the registers before I2C read:
lsr 0x61 ier 0x01 iir 0xCC rxlvl 0x18
b)The init code of the chip is:

{SC16IS750_REG_IER,0},// no IRQ
{SC16IS750_REG_FCR,0x06}, //  reset TXFIFO, reset RXFIFO, non FIFO mode
{SC16IS750_REG_LCR,0x80},  // program baudrate
{SC16IS750_REG_DLL,0x80},  // 2400
{SC16IS750_REG_DLH,0x01},
{SC16IS750_REG_LCR,0x03},  // 8 data bit, 1 stop bit, no parity
{SC16IS750_REG_FCR,0x81}, //  enable FIFO mode, RX trigger level 56 char,expect timeout intr
{SC16IS750_REG_IER,0x01}, // Receive Holding Register interrupt only  

c) For SCL and SDA I am using 10k pullups
d) Here a picture of SCL (2) and SDA (1); I slowed down the speed to approx >5us for the clock

Image of SCL and SDA

some more additions:
I do have read the technical notes from NXP on this issue. However I continued trying to get multiple read working without success: Here the latest init sequence - I added some delay (100usec) between writing the registers:

    unsigned char  sc16is750_reg_init[][2] = {
        {SC16IS750_REG_LCR,0x80},  // program baudrate
        {SC16IS750_REG_DLL,0x80},  // 2400
        {SC16IS750_REG_DLH,0x01},
        {SC16IS750_REG_LCR,0xBF},  // access EFR register
        {SC16IS750_REG_EFR,0x10}, // enable enhanced registers
        {SC16IS750_REG_LCR,0x03},  // 8 data bit, 1 stop bit, no parity
        {SC16IS750_REG_MCR,0x04},  // enable TLR and TCR
        {SC16IS750_REG_TLR,0x60},  //set TLR 24 char RX
        {SC16IS750_REG_FCR,0x06}, //  reset TXFIFO, reset RXFIFO
        {SC16IS750_REG_FCR,0x01}, //  enable FIFO mode
        {SC16IS750_REG_IER,0x01}, // receive line status IRQ only
        {0xff,0xff}  
    };  

Actually I want an interrupt to be generated if Fifo conatins 24 char. This is why I setup TLR register. This works fine. This means that setting up the register do work. The sequence is in line with the NXP technical note. I'll read the following content out of the registers in ther interrupt service routine:

iir 0xC4 lsr 0x61 rxlvl 24    

So 0xC4 means Fifo level interrupt, no overflow. When I do a multiple reads I'll get:

010000000000000000000000000000000000000000000000

If I used the same function but read single characters only I'll get:

010231353A333520536F2030332E30392E323031370000B1

The other interessting point to mention is - I'll can do a multiple write.

\$\endgroup\$
3
  • \$\begingroup\$ (a) "Read interrupt status register IIR, Read Line Status register LSR, Read RX Level register RXLVL" What values do you read from each of those registers, at that point? (b) Can you share your SC16IS750 init code (please add it, at the end of your question) or is it secret? (c) What value pull-ups have you added to SDA & SCL? (d) Just to confirm the I2C waveform shapes, have you checked them with a scope? If so, can you supply that scope trace? \$\endgroup\$
    – SamGibson
    Commented Aug 29, 2017 at 19:22
  • \$\begingroup\$ Hello Sam, thanks for your help. See my answers above. \$\endgroup\$
    – Emi
    Commented Aug 30, 2017 at 17:52
  • \$\begingroup\$ Thanks for that information. After some further research, I've written my analysis and suggestions in an answer. \$\endgroup\$
    – SamGibson
    Commented Sep 2, 2017 at 6:17

2 Answers 2

2
\$\begingroup\$

Short version: I recommend changing the register initialisation sequence (see the end of this analysis below).

Here is the long version of my review of the information supplied:

  • Register contents before starting to read data

    lsr 0x61 ier 0x01 iir 0xCC rxlvl 0x18

    That all looks sensible, although obviously that is with 0x18 (24) characters in the FIFO and not the 16 characters which was mentioned in the question.

  • Line Status Register (LSR)

    Your pseudo-code mentions only reading that register once. It's not part of your problem, but note that LSR[7] tells you about an error anywhere in the FIFO; however LSR[4:2] tells you about the character only at the top of the FIFO. Therefore reading LSR just once, before reading all characters in the FIFO, will not reveal that status about each character.

  • I²C waveform shape

    I'm a bit concerned that we are not reviewing the "normal" waveform, because you mention that you "slowed down the speed to approx >5us for the clock" for that photo. However, at the clock speed in that photo (which looks around 50 kHz) the waveform shape, and therefore the pull-up resistor value, is OK.

    I assume that you reproduced the problem in your question, at the I²C clock speed shown on that oscilloscope photo.

  • Initialisation sequence

    The SC16IS750 datasheet doesn't include a recommended sequence of register programming, to setup the device. In that situation, to avoid reinventing the wheel, I suggest looking for other examples including code written by other people, as a starting point - even if those code examples don't do exactly what you want. Confirm that they work as they say they should. Then, if needed, modify them step-by-step towards your goal.

    Your initialisation code is:

    {SC16IS750_REG_IER,0},// no IRQ
    {SC16IS750_REG_FCR,0x06}, //  reset TXFIFO, reset RXFIFO, non FIFO mode
    {SC16IS750_REG_LCR,0x80},  // program baudrate
    {SC16IS750_REG_DLL,0x80},  // 2400
    {SC16IS750_REG_DLH,0x01},
    {SC16IS750_REG_LCR,0x03},  // 8 data bit, 1 stop bit, no parity
    {SC16IS750_REG_FCR,0x81}, //  enable FIFO mode, RX trigger level 56 char,expect timeout intr
    {SC16IS750_REG_IER,0x01}, // Receive Holding Register interrupt only  
    

    I found 4 different initialisation sequences. I cannot test them myself, without having one of these devices, but I suggest trying them as a starting point as I explained above.

    1) From page 5 in the NXP Application Note AN10462 - SPI programming for Philips Bridge ICs (I don't see any reason for the initialisation sequence to be different between the SPI and I²C interfaces on that device, so ignore that this is written as an SPI-based example):

    void init_SC16IS750 (void) {
    SPI_write (LCR, 0x80); // 0x80 to program baud rate
    SPI_write (DLL, 0x30); // 0x30=19.2K, 0x08 =115.2K with X1=14.7456 MHz
    SPI_write (DLM, 0x00); // divisor = 0x0008 for 115200 bps
    SPI_write (LCR, 0xBF); // access EFR register
    SPI_write (EFR, 0X10); // enable enhanced registers
    SPI_write (LCR, 0x03); // 8 data bit, 1 stop bit, no parity
    SPI_write (FCR, 0x06); // reset TXFIFO, reset RXFIFO, non FIFO mode
    SPI_write (FCR, 0x01); // enable FIFO mode
    }
    

    2) From page 7 in the NXP Application Note AN10587 - Interfacing NXP bridge IC with NXP ARM microcontroller (again this is an SPI-based example, it's for the 2-channel version of the device, and it includes initialisation of the GPIO pins, however the relevant parts of the initialisation sequence are clear):

    Void SC16IS752_Init_ChA (void) // program channel A for SPI-UART
    { // set 115200 baud, 8N1
    SPI_wr_752 (LCR, 0x80, 0); // 0x80 to program baud rate
    SPI_wr_752 (DLL, 0x08, 0); // 0x08 = 115.2K with X1 = 14.7456 MHz
    SPI_wr_752 (DLM, 0x00, 0); // divisor = 0x0008 for 115200 bps
    SPI_wr_752 (LCR, 0xBF, 0); // access EFR register
    SPI_wr_752 (EFR, 0X10, 0); // enable enhanced registers
    SPI_wr_752 (LCR, 0x03, 0); // 8 data bit, 1 stop bit, no parity
    SPI_wr_752 (FCR, 0x01, 0); // enable FIFO mode
    SPI_wr_752 (SPR, 'A', 0); // scratch pad = character A (0x41)
    SPI_wr_752 (IODIR, 0xFF, 0); // set GPIO [7:0] to output
    // (default: 0x00=input)
    SPI_wr_752 (IOSTATE, 0x00, 0); // set GPIO [7:0] to 0x00 (LEDs on)
    SPI_wr_752 (IER, 0x01, 0); // enable Rx data ready interrupt
    }
    

    3) From this mbed code library:

    cmd[0] = LCR << 3;
    cmd[1] = 0x83;          // DLL,H Latch enable
    i2c.write(SC16IS750_ADDR, cmd, 2);
    
    cmd[0] = DLL << 3;
    cmd[1] = 117;           // baud = 18e6 / 16 /117 = 9615 
    i2c.write(SC16IS750_ADDR, cmd, 2);
    
    cmd[0] = DLH << 3;
    cmd[1] = 0x0;
    i2c.write(SC16IS750_ADDR, cmd, 2);
    
    cmd[0] = LCR << 3;
    cmd[1] = 0x03;        // NoParity 1Stop 8bits
    i2c.write(SC16IS750_ADDR, cmd, 2);
    
    cmd[0] = FCR << 3;
    cmd[1] = 0x07;        // reset TX,RX FIFO, FIFO enable
    i2c.write(SC16IS750_ADDR, cmd, 2);
    

    4) There is another mbed library containing another initialisation example. However that code is more complex and it is difficult to extract only the relevant parts to include here. It's simpler for you to read this one at its original location.

    (It is also worth noting that this device claims to have a 16C450-compatible register set (actually it is more like a 16550, since it has a FIFO, or even a 16750, since it has a 64-byte FIFO). You can review old 16550 UART literature about how that device is usually initialised. From my quick research, a sequence similar to example 2 is typical.)


  • One difference (which I suspect is important) between those other initialisation examples and your code, is that none of them initialise FCR at the start and end of the sequence, as your existing code does. They either write to FCR only once (examples 2 & 3) or write to FCR twice in succession, with other registers programmed before that (examples 1 & 4).

    On page 22 of the SC16IS750 datasheet is "note 4" regarding FCR, where it says:

    After Receive FIFO or Transmit FIFO reset (through FCR[1:0]), the user must wait at least 2 x Tclk of XTAL1 before reading or writing data to RHR and THR, respectively.

    (As an aside, there seems to be a mistake in that note - Receive FIFO & Transmit FIFO reset bits are FCR[2:1] not FCR [1:0])

    I don't know the timing of your code, to see whether it reads RHR too quickly after resetting the FIFO. On the surface, it seems unlikely that you are breaking that requirement - 2 clock cycles of whatever crystal Sparkfun use on your specific board (e.g. 12.288 MHz or 14.7456 MHz - check your board) is a very short minimum delay, especially when using a comparatively slow I²C bus to send commands. However I wonder if there is a hidden issue in this timing requirement, since it is measured in clock cycles of the crystal. See below where I mention the "Power-on sequence".

    So as you see, it is implied by that datasheet note, that writing to (at least certain bits in) FCR has some internal timing dependencies. Your existing code does modify other registers, after setting the Receive FIFO & Transmit FIFO reset bits in FCR. If there is one place where a lack of mentioning other side effects in the datasheet might affect you, but not affect the other example code which I found, then it could be in this area.

  • Another interesting point discussed in section 7.4.2 "Power-on sequence" in the datasheet, is the potential need for delay after power-on. As I interpret it, you should not attempt to program the registers until at least 3 µs after power-on (or after external reset pulse). That requirement may not affect you during a normal power-on, as your MCU etc. will also be initialising.

    However notice the next part [my emphasis added]:

    Once the device is reset properly, the host processor can start to communicate with the device. Internal registers can be accessed (read and write), however, at this time the UART transmitter and receiver cannot be used until there is a stable clock at XTAL1 pin. Normally, if an external clock such as a system clock or an external oscillator is used to supply a clock to XTAL1 pin, the clock should be stable at this time. But if a crystal is used, the host processor must wait until the crystal is generating a stable clock before accessing the UART transmitter or receiver.

    The crystal’s start-up time depends on the crystal being used, VCC ramp-up time and the loading capacitor values. The start-up time can be as long as a few milliseconds.

    That time is shown as "tstartup" in the following diagram - but as they say, the actual duration of tstartup is unknown, as it depends on your specific hardware.

    Having explained the background, here is the main point: Perhaps that requirement in the datasheet ("note 4" on page 22) for a delay of "at least 2 x Tclk of XTAL1 before reading or writing data to RHR and THR" after resetting the FIFO, cannot start until after the crystal output is stable (i.e. until after "tstartup" has elapsed) since it is measured in clock cycles of the crystal, and you don't know when the crystal has actually started.

    If you have a crystal which is slow to start, these timing requirements could be affecting you.


Therefore I would:

  1. Change the initialisation sequence to match one of the other examples (assuming that those other example initialisation sequences do work correctly).

    Examples 1 & 2 are from the device manufacturer, so they should work!

    and

  2. Consider whether one or more delays might need to be added during the register initialisation sequence, to comply with the worst-case timing requirements explained in the datasheet.

Personally I would start with option 1.

\$\endgroup\$
4
  • \$\begingroup\$ Hello Sam, Thanks for your answer. I'll added some more notes to the question. \$\endgroup\$
    – Emi
    Commented Sep 5, 2017 at 13:02
  • \$\begingroup\$ @Emi - Although the reported "multiple read" behaviour (1st char read OK, subsequent chars read as 0x00) fits with the FIFO not being enabled, the "single read" behaviour suggests that it is enabled. I have done more research since you posted the update. Unfortunately, without having your hardware and software in my hands, it would be unrealistic for me to try to "remotely" describe each test which I want to run in the necessary detail, especially since I could not run the tests here first. I can only suggest you wait for someone who already has this device, to add their answer. Good luck! \$\endgroup\$
    – SamGibson
    Commented Sep 9, 2017 at 18:44
  • \$\begingroup\$ you made a good point. Reading "0" after the first byte may indicate that FiFo is disabled. However I read 0xC4 for IIR which means FiFo enabled. If I read only eg 16 bytes when receiving an FiFo interrupt with RxLev 24 then afterwards RxLev shows 8 and LSR BIT0 still set. This means for what ever reason Bytes are not moves from FiFo to RHR during multiple read, but counters are handler correctly. This is strange. Bytes are only moved when doing single reads. I'll do that at the moment but this takes much more time - unfortunately. \$\endgroup\$
    – Emi
    Commented Sep 12, 2017 at 11:58
  • \$\begingroup\$ @Emi - Other places where you could ask for help include (a) The public NXP "Technical Communities" - I think that this is the correct one: community.nxp.com/community/other since that IC doesn't fit into their other "communities"; or (b) Raise a "support ticket" directly to NXP, after you have registered: nxpcommunity.force.com/community/CommunityContextPage || If you do solve the problem, please come back and write an answer (people can answer their own questions here) :-) Good luck! \$\endgroup\$
    – SamGibson
    Commented Sep 12, 2017 at 12:20
2
\$\begingroup\$

Finally I found the problem. I am using an ESP8266 as I2C master. The issue was in the low level driver of the getBit function - here the fixed/working version:

uint8 i2c_getBit() {
    uint8 retVal;
    ETS_INTR_LOCK();
    GPIO_OUTPUT_SET(I2C_MASTER_SDA_GPIO, 1) ;
    wait1(); //data set-up time
    GPIO_OUTPUT_SET(I2C_MASTER_SCL_GPIO, 1) ;
    wait2(); // HIGH period of the SCL clock
    retVal = GPIO_INPUT_GET(I2C_MASTER_SDA_GPIO);
    GPIO_OUTPUT_SET(I2C_MASTER_SCL_GPIO, 0) ;
    wait3();// LOW period of the SCL clock
    ETS_INTR_UNLOCK();
    return retVal;
}

The issue was - if one does not set SDA to HIGH before SCL HIGH & read one cannot read multiple bytes ie I needed to include

GPIO_OUTPUT_SET(I2C_MASTER_SDA_GPIO, 1);  

at the beginning of the function.
After further analysis I now understand what happens:
The GPIO pins are configured as open drain ie if a "1" is written to the GPIO register the line is released and the pullup put the line to "1".
In the case above the master sends after the repeated start the address plus READ which is a "1" as last bit on the line (master releases the line!). The slave answers with an ACK ie "0" and 8 data bits. Now the master must send an ack ie "0". Without writing a "1" the line will not be released by the master. That causes that all the following BITS will be read as "0". To avoid that the master must send a "1" before SCL=1 and reading SDA.

\$\endgroup\$
2
  • \$\begingroup\$ @SamGibson - as you may read I found the answer by myself after code reading and investigating what happens on the line. As usual once one has analysed what happened it's easy to understand what was wrong. Thanks again for your help and hints. \$\endgroup\$
    – Emi
    Commented Sep 17, 2017 at 19:32
  • \$\begingroup\$ Thanks for the update. I'm glad you found the bug in the code :-) When you looked at the full oscilloscope trace of the multi-read I2C transaction, the problem must have been obvious, with SDA stuck low after the first byte :-( Well done! \$\endgroup\$
    – SamGibson
    Commented Sep 18, 2017 at 0:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.