This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RM46L430: SPI BUF TXFULL flag is not being set

Part Number: RM46L430
Other Parts Discussed in Thread: HALCOGEN

Hello All,

I'm trying to write an SPI driver that the is using a MiBSPI via both polling and transfer groups.

The transfer group / MiB part is working well, the polling on the other hand, is causing me problems!

The datasheet, SPNU514B April 2015 - Table 27-24. SPI Receive Buffer Register (SPIBUF) Field Descriptions says:

Transmit data buffer full.This flag is a read-only flag. Writing into the SPIDAT0 or SPIDAT1 field while the TX shift register is full will automatically set the TXFULL flag. Once the word is copied to the shift register, the TXFULL flag will be cleared. Writing to SPIDAT0 or SPIDAT1 when both TXBUF and the TX shift register are empty does not set the TXFULL flag.

My understanding is that this flag is completley managed by the controller and each time that it is '0'  I can write data into SPIDAT1. My problem is that this flag is never being set and the polling algorithm always thinks that the TXBUF is free. As a result, a tranfer of 7 SPI frames results in only frames 1, 4 & 7 appearing on a logic analyser. I have logged the all of the SPIBUF reads that occur during the polling, of which there are around 64 before a software timeout, and at no point does the TXFULL flag get set. The RXEMPTY flag does behave based on my understanding of the datasheet. I put a debug GIO pulse around the write to the SPIDAT1 and I can see that the polling is writing three times to the SPIDAT1 register before the first 2 MHz 8-bit frame completes its transfer. This seems to contradict the data sheet as the TX Shift Register and the TXBUF should both be full after the second write.

I have looked in the HalCoGen code for insperation and it uses bit 8 of the SPIFLG register (RXINTFLG) to determine that the transfer is complete. This is not a very efficient implementation as it causes gaps between the transmitted frames. The TXFULL flag mechanism ensures that the TX Shift Register is loaded immediatley after the completion of a frame as the TXBUF is kept full.

I have checked the ERRATA and cannot find anything relevant.

Can someone please correct my misunderstanding of this mechanism?

  • Hi Mark,

    I think there is a bit of a discrepancy in the description of the bit in the register section vs the description of the setting of the flag relative to the data flow in section 27.2.2.1 which states the following:

    27.2.2.1 Data Sequencing when SPIDAT0 or SPIDAT1 is Written
    • If both the TX shift register and TXBUF are empty, then the data is directly copied to the TX shift
    register. For devices with DMA, if DMA is enabled, a transmit DMA request (TX_DMA_REQ) is
    generated to cause the next word to be fetched. If transmit interrupts are enabled, a transmitter-empty
    interrupt is generated.
    • If the TX shift register is already full or is in the process of shifting and if TXBUF is expty then the data
    written to SPIDAT0 / SPIDAT1 is copied to TXBUF and TXFULL flag is set to 1 at the same time.
    • When a shift operation is complete, data from the TXBUF (if it is full) is copied into TX shift register
    and the TXFULL flag is cleared to 0 to indicate that next data can be fetched. A transmit DMA request
    (if enabled) or a transmitter-empty interrupt (if enabled) is generated at the same time.

    Per the description above, TXFULL will be set when data is moved from SPIDAT0/1 to the TXBUF register. TXFULL flag will be cleared when data is moved from the TXBUF to the TXSHIFT register.

    This is slightly different than the description quoted in that the data flow states the flag is set based on the state of TXBUF not the TXShift register.

    In regard to servicing this implementation based on the state of the TXFULL flag in a rapidly changing bit streaming like use case, I think it is likely that the TXFULL condition will be very difficult to see/capture given the latency of the CPU access to the peripheral in order to write the SPIDAT0/1 register data and the smaller latency of the movement of data between the SPIDAT0/1 registers to the TXBUF register and subsequently to the TXShift register. The peripheral access latency in Hercules is on the order of magnitude of 20-25 cycles where the latency between the TXBuff and TXShift register will be just a few VBUSP cycles. In short, by the time you load SPIDAT0 and it is transferred into TXBUF it would be transferred to the TXSHIFT register before you would have time to then load the SPIDAT1 register and vice versa. Therefore, it would truly be a rare occasion for the TXFULL flag to be set unless the slave held off the master TX for some reason.
  • Hi Chuck,

    Thanks for taking the time to answer, but I'm not sure that I follow the logic behind your answer:

    • If I write to SPI1DAT and the TX shift register is empty then it will write directly to the TX shift register, after which TXFULL should indicate empty:
      • (27.2.2.1) If both the TX shift register and TXBUF are empty, then the data is directly copied to the TX shift register. For devices with DMA, if DMA is enabled, a transmit DMA request (TX_DMA_REQ) is generated to cause the next word to be fetched. If transmit interrupts are enabled, a transmitter-empty interrupt is generated.

    • If I write to SPI1DAT and the TX shift register is busy shifting out data then it will write to TXBUF, after which TXFULL should indicate full:
      • (27.2.2.1) If the TX shift register is already full or is in the process of shifting and if TXBUF is expty then the data written to SPIDAT0 / SPIDAT1 is copied to TXBUF and TXFULL flag is set to 1 at the same time.

    • After the TX shift register is finished shifting out the data it will copy the next data from TXBUF, after which the TXFULL should indicate empty:
      • (27.2.2.1) When a shift operation is complete, data from the TXBUF (if it is full) is copied into TX shift register and the TXFULL flag is cleared to 0 to indicate that next data can be fetched. A transmit DMA request (if enabled) or a transmitter-empty interrupt (if enabled) is generated at the same time.

    This mechanism ensures that the TXBUF is permanently loaded and the TX shift register never stalls waiting for the data for the next frame.

    If I'm not mistaken (and sometimes I am) you have not taken into account of the time that it takes for the shift operation get all of the data out on the SIMO.

    In answer to two lines of you reply:

    > In short, by the time you load SPIDAT0 and it is transferred into TXBUF it would be transferred to the TXSHIFT register before you would have time to then load the SPIDAT1 register and vice versa

    It can only transfer the data to 'TXSHIFT' once the shifting process is complete and this is taking 4µs per frame. 

    > Therefore, it would truly be a rare occasion for the TXFULL flag to be set unless the slave held off the master TX for some reason.

    It's not the slave that is holding off the master, it's the 4µs transfer time of the 8-bit frame. The master is 'holding off' itself.

    Based on the following:

    • 20-25 clock peripheral latency at 200MHz ->a latency of 125ns.
    • 2MHz SPI with an 8-bit frame -> a frame transmit time of 4µs.
    • The program code is running from TCM (no FLASH pipeline overhead) at 200MHz.
    • The logic analyser shows four writes to SPI1DAT during the 4µs of the first SPI frame transmission.
    • A log of all polled SPIBUF reads (around 60 or so) shows that TXFULL never indicates full, but RXEMPTY flag values are as expected.

    The logic analyser shows:

    Notes on the 'diagram':

    • Write to SPIDAT1 is a GIO pulse around the SPI1DAT register write.
    • Read RXBUF with data is a GIO pulse around the read of the SPIBUF that indicates new data.

    Some additional observations:

    • 27.2.2.1 says 'and if TXBUF is expty then the data written', but based on the read data sequence in the logic analyser trace it shows that a SPIDAT1 write to a full TXBUF overwrites and does not discard.

    • I have also noticed that if the TXBUF is kept full then there is no need to manage the CSHOLD bit in the SPI1DAT as the controller appears happy to send back-to-back SPI frames without and inter-frame gap or removing and reasserting the chip select. Is this expected functionality? If it is then it makes the transfer algorithm simpler and faster as there is less setup before the polling loop (faster) and more frequent polling (higher polling resolution and can finish quicker).

    Regards,

    Mark.

  • Hi Chuck,

    You said:

    > Therefore, it would truly be a rare occasion for the TXFULL flag to be set unless the slave held off the master TX for some reason.

    The master is being 'held-off' by the 4µs transmit of the 8 SPI bits, so I am expecting the TXFULL flag to be set.

    Regards,

    Mark.

  • Hello Mark,

    I believe I stated that 'IF' the master was being held off for some reason such as the use of nENA or a C2T delay value. I assume in your implementation there are no such delays since you want a contiguous bit stream.

    So my point I was trying to make was if you are continuously toggling between SPIDAT0 and SPIDAT1 and filling alternately, and continuously recieving data then perhaps the timing was such that the condition is never satisfied. After some additional discussion and investigation, I don't think this is your problem, though.

    During the past few days I have been dealing with a similar issue where the customer is trying to receive/transmit data without any gaps in the bit stream. I found there are limitations to this. If the TMS570 is the slave, the VCLK to SPICLK ratio must be >1/16 in order for there to be sufficient time for the TXRAM/SPIDAT1 content to be transferred into the SPISHIFT register for transmit. i.e., a gap between transmissions is required. Since your application is using a SPICLK of 2MHz, I assume this is well within the requirement.

    However, there is another fact that came up as well. During transmissions, either SPIDAT0 or SPIDAT1 is used not both. This is the case within the SPI transmit routines provided by Halcogen. This may be why you are seeing only some of the data be transmitted. Can you check to see if you limit your application to only using SPIDAT1, all data is transmitted as intended. This may clear up a lot of the issues you are seeing.
  • Hello Chuck,

    I only use SPIDAT1 and my current implementation is:

    The 'TX?' decision always takes the 'yes' path as the TXFULL bit is always 0.

    The following table shows SPIBUF log from the 'Read SPIBUF (and log its value)' action in the flow chart:

    SPIBUF Value Status Bits RXEMPTY TXFULL Action   Triggered
    803E00E5 10000000 1 0 Write frame 1
    803E00E5 10000000 1 0 Write frame 2
    803E00E5 10000000 1 0 Write frame 3
    803E00E5 10000000 1 0 Write frame 4
    003E00E5 00000000 0 0 Write frame 5, extract read data
    803E00E5 10000000 1 0 Write frame 6
    003E00F7 00000000 0 0 Write frame 7, extract read data
    803E00F7 10000000 1 0 None
    803E00F7 10000000 1 0 None
    803E00F7 10000000 1 0 None
    803E00F7 10000000 1 0 None
    003E00FF 00000000 0 0 Extract read data
    803E00FF 10000000 1 0 None
    803E00FF 10000000 1 0 None
    803E00FF 10000000 1 0 None
    803E00FF 10000000 1 0 None

    At no point is the TXFULL bit set. You can see the result of this on the logic analyser trace in my other post.

    Why does the write of frame 2 not result in TXFULL? Frame 1 is copied directly to TXSHIFT and the data starts shifting. Frame 2 is copied to TXBUFF as TXSHIFT is busy, TXFULL should now be set and should stay set until the next TXBUF transfer to TXSHIFT. I can see (roughly) when the data was finished shifting as the RXEMPTY flag changes, which means that around this time is the point where the TXFULL show change back to a 0. There are 4 polling cycles before the first RXEMPTY flag change, which means that at least two of them (Write frame 3 & 4) meet the TXFULL criteria of TXSHIFT busy and TXBUFF full.

    Please explain to me why I should not expect the TXFULL bit set. The above log seems to contradict the user manual.

    In you first post you said:

    > ...it is transferred into TXBUF it would be transferred to the TXSHIFT register before you would have time to then load the SPIDAT1 register...

    But, if the TXSHIFT register is not ready for a new value, as it's currently shifting, then there is plenty of time to load the SPI1DAT register again as TXSHIFT is busy for 4µs (2MHz 8-bit), the peripheral latency is 125ns (20-25 clocks)and the program code is running at 200MHz from the TCM.

    Regards,

    Mark.

  • Hi Chuck,

    I'm writting to the SPIDAT1 faster than TXSHIFT can serialise and shift out the bits, yet at no point does TXFULL get set.

    The User's Manual says:

    (27.2.2.1) If the TX shift register is already full or is in the process of shifting and if TXBUF is expty then the data written to SPIDAT0 / SPIDAT1 is copied to TXBUF and TXFULL flag is set to 1 at the same time.

    You have said that I have misunderstood the User's Manual. So please explain to me why the TXFULL is not set, as the User's Manual statement above seems quite clear

    Regards,

    Mark.

  • Mark,

    Sorry for the gap in answering on this thread. If you have a look at our spi drivers, we use the RXFlag to indicate when to write to SPIDAT1 next. This means only after all data has been shifted out and receive data shifted in. As I understand, this process is too slow for your desired behavior? If you use the existing SPI drivers in this manner, how far short is the gap between transmissions? Note per my prior post, there has to be some gap between transmissions per the IP design and time for shifting data from TXBUFF to TXSHIFT.
  • Hi Chuck,

    Yes, there is always a gap between the frames, even when the MibSPI is in use.

    But in my previous post you can see from the logic analyser capture that the polled version of the algorithm can write as fast as the Transfer Group version.

    The only problem I have is that the TXFULL flag DOES NOT WORK as specified.

    I have performed a test:

    Set 1MHz SPI 16 bit word

    Set result to 0

    Loop 10 times:

    Write to SPI1DAT to transmit word

    Read SPIBUF and ‘OR’ into result

    Checked ‘OR’ SPIBUF result

    The ‘OR’ result does not have the TXFULL bit set and I see one transmitted 16 bit word. I’m quite sure that the TXSHIFT and TXBUF are both full for most of the transfer, yet no TXFULL is recorded.

    Please explain to me how the why the TXFULL does not behave as specified in the user’s manual?

    Regards,

    Mark.

  • Hi Mark,

    Let me check with our IP design team on this to see if they may have any insights or known issue with this. FYI, since they are in a different time zone and not dedicated support, it may take a few days for them to get back with me.
  • Hi Mark,

    This is the detailed information I received from the module designer.

    "The behavior observed is expected and correct.

     

    Please note that when user writes the first data to SPIDATx register, it gets copied into the Shift Register directly – TXFULL remains ‘0’. Only when you write another data to SPIDATx register, if Shift Register is still shifting data, the written data will be copied to the TXBUF register. Now the TXFULL flag will be set indicating that buffer is full. This is exactly what is explained in the MibSPI spec – snapshot below.

     

    Please refer also to the Figure 1 in the MibSPI to get a clearer view of the logic structure.

     

    In general, if user is feeding data using CPU, then it would be good to write two of the data back-to-back (this fills both TX Shift Register and TXBUF) in the beginning. After that point, keep polling for TXFULL flag to feed the next set of data. This allows best throughput of data. It works as below.

    1. First data in TX Shift Register is shifted out.

    2. As soon as this shift is completed, data from the TXBUF (which is the 2nd data) is copied to the TX Shift Register by the hardware logic and the TXFULL flag is cleared to ‘0’.

    3. If SW writes the next data to SPIDATx register, that will be copied to TXBUF and the TXFULL flag will be set to ‘1’.

    4. When the 2nd data shift is completed, TXBUF content (if it’s full already - indicated by TXFULL flag) will be copied to TX Shift register by the hardware logic and the TXFULL flag is cleared.

       

    This cycle continues as long as new data keeps getting fed into SPIDATx register as soon as TXFULL flag is cleared to ‘0’. User basically has a window of one SPI transfer from the time TXFULL is cleared to ‘0’ to write the next data to keep the IDLE cycles between two transfers to the minimum.

     

    Basically, user needs to use the TXFULL flag as a way to determine if the next data to SPIDATx register can be written or not. If TXFULL flag is ‘0’, it means user can write the next data immediately."

  • Hi Chuck,

    'user needs to use the TXFULL flag as a way to determine if the next data to SPIDATx register can be written or not' is exactly what I am trying to achieve, but the flag is never set!

    Are there any other settings to make this flag work?

    Why does the HaCoGen code use the RX flag? Is it because the integrator could not get the TXFULL flag to work?

    Regards,

    Mark.
  • Hi Mark,

    Yes, I understand this is what you are trying to do. The reason for copying the experts post directly was to insure you are following the exact process that he has outlined.

    I am not certain of the exact reason for the use of the Rx flag in the code. I would guess that it is because there is some certainty that once the Rx flag is set, the data in TXBUFF has been transmitted/shifted out. I'm not certain there was ever an effort to optimize the code in the manner you are working towards. However, the TXFULL functionality was validated in the design phase where internal workings of the buffers could be better controlled.

    Have you tried slowing down the period at which the TX occurs to guarantee that the condition of TXFULL is met?