• AVR Freaks

Hot!Using 2 SPI bus with TLC4545

Author
antal_peter
New Member
  • Total Posts : 22
  • Reward points : 0
  • Joined: 2013/10/27 00:08:03
  • Location: Hungary
  • Status: offline
2019/05/08 05:15:41 (permalink)
0

Using 2 SPI bus with TLC4545

I have problem with interfacing TLC4545 to dsPic33FJ256GP506A. I use 2 TLC4545. One for SPI1 bus and the other on SPI2 bus.
The bus initialization:
void AD_init(void)
{
 
TRIS_AD1;                                                                           // chip select is output
AD1_CS = 1;                                                                        //Disable chip select
UNSELECT_MMC();                                                               // SD card unselect to free MOSI line
 
_SPIEN                                       = 0;                                   // Disable SPI1 modul 
SPI1CON2bits.FRMEN                   = 0;                                  // Framed support disabled
SPI1CON2bits.FRMDLY                  = 0;                                  // Frame sync prec. data transm.
SPI1CON2bits.SPIFSD                   = 0;                                 // Framed master mode
SPI1CON1bits.MODE16                 = 0;                                  // Communication is byte wide
SPI1CON1bits.MSTEN                    = 1;                                 // Master mode enable
SPI1CON1bits.SMP                         = 0;                                 // Data sampled at end of data time
SPI1STATbits.SPISIDL                     = 0;                                // Cont. module op. in Idle mode
SPI1CON1bits.DISSCK                    = 0;                                 // Internal SPI clock is enabled
SPI1CON1bits.DISSDO                   = 0;                                  // SDO is controlled by the module
SPI1STATbits.SPIROV                     = 0;                                  // No receive overflow has occured
SPI1CON1bits.SSEN                        = 0;                                 // Not used in master mode !!!
SPI1CON1bits.CKP                          = 0;                                 // Clock polarity  0= idle
SPI1CON1bits.CKE                           = 1;                                // Data valid at falling edge of clock
SPI1CON1bits.SPRE                          = 0b111;                        // Prescale 1:4  CLK= 2 228 587 Hz
_SPIEN                                            = 1;                              // Enable SPI1 modul
 
TRIS_AD2;                                                                              // chip select is output
AD2_CS = 1;                                                                           //Disable chip select
 
SPI2STATbits.SPIEN                        = 0;                                   // Disable SPI2 modul !!
SPI2CON2bits.FRMEN                     = 0;                                    // Framed support disabled
SPI2CON2bits.FRMDLY                   = 0;                                     // Frame sync precedes data
SPI2CON2bits.SPIFSD                    = 0;                                       // Framed master mode
SPI2CON1bits.MODE16                 = 0;                                       // Communication is byte wide
SPI2CON1bits.MSTEN                    = 1;                                       // Master mode enable
SPI2CON1bits.SMP                         = 0;                                     // Data sampled at end of data time
SPI2STATbits.SPISIDL                     = 0;                                     // Cont. module op. n in Idle mode
SPI2CON1bits.DISSCK                    = 0;                                      // Internal SPI clock is enabled
SPI2CON1bits.DISSDO                   = 0;                                       // SDO is controlled by the module
SPI2STATbits.SPIROV                     = 0;                                       // No receive overflow has occured
SPI2CON1bits.SSEN                        = 0;                                       // No slave sync
SPI2CON1bits.CKP                          = 0;                                        // Clock polarity  0= idle
SPI2CON1bits.CKE                           = 1;                                        // Data valid at falling edge of clock
SPI2CON1bits.SPRE                        = 0b111;                                  // Presale divide by 0
SPI2CON1bits.PPRE                        = 0b10;                                   // Prescale 1:4
SPI2STATbits.SPIEN                        = 1;                                        // Enable SPI2 modul
 
I do the reset cycle for both TLC4545 I got back the FF00 to acknowledge the reset. But when I use the following read cyle for both TLC4545 I have got two different pattern:
 
void if_spixSend()

    int i;
                GREEN_LED^=1;
                SPI1STATbits.SPIROV=0;                      
                AD1_ENABLE;                         // Data conversion start
    Nop();
                SPI1BUF = 0;                                      // Start to transmit/receive 0-7 bit   
    While (! SPI1STATbits. SPIRBF);                        // wait 8 bit receive  
     *ARp=SPI1BUF<<8; 
    SPI1BUF = 0;                                                   // Start to 8 bit clock 8-15 bit
    while(!SPI1STATbits.SPIRBF);                            // wait 8 bit receive
    (*ARp++) +=SPI1BUF;
    SPI1BUF =0;                                                    // Start to 8 bit clock 16-24 bit
    while(!SPI1STATbits.SPIRBF);                           // wait 8 bit clock transmit
    for(i=1; i<7; i++);                                          // Timing for CS                     
    AD1_DISABLE;
   
    SPI2STATbits.SPIROV=0;                                 // Data conversion start
    AD2_ENABLE;
    Nop();
    SPI2BUF =0;                                                  // Start to transmit/receive 0-7 bit   
                while(!SPI2STATbits.SPIRBF);
    *ARp=SPI2BUF<<8;
    SPI2BUF =0;                                                 // Start to transmit/receive 0-7 bit
                while(!SPI2STATbits.SPIRBF);
    (*ARp++) += SPI2BUF;
    SPI2BUF = 0;                                               // Start to 8 bit clock 16-24 bit
    while(SPI2STATbits.SPIRBF);                        // wait 8 bit clock transmit
    for(i=1; i<8; i++);
    AD2_DISABLE;
                return;
}
 The first picture shows the SPI1 Bus after initialization while the second shows the SPI2 bus.
The read values 0EFF and ECFF instead of FF00
 
 
What would be wrong?

Attached Image(s)

#1

15 Replies Related Threads

    du00000001
    Just Some Member
    • Total Posts : 3065
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/08 05:33:40 (permalink)
    4.5 (2)
    Look at the following image! Can you see "something" ?
     
     

    Attached Image(s)


    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #2
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/08 09:51:20 (permalink)
    0
    Yes, the TLC 4545 require the idle low polarity

    Attached Image(s)

    #3
    du00000001
    Just Some Member
    • Total Posts : 3065
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/08 09:53:33 (permalink)
    4 (1)
    What about the difference in setting .PPRE ?

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #4
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/08 10:04:26 (permalink)
    0
    There is no difference in PPRE both set to 0b10. Actually the clock is 2 228 587 Hz
    #5
    du00000001
    Just Some Member
    • Total Posts : 3065
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/08 11:12:56 (permalink)
    4.5 (2)
    In your posted code, the setting of .PPRE for SPI is missing. Can't you see that?
    (Why do you think did I post this side-by-side list?)

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #6
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/09 02:04:16 (permalink)
    0
    Sorry I got it. It is only a copy paste problem. 
     
    SPI1CON1bits.PPRE = 0b10;                             // Prescale 1:4  CLK= 2 228 587 Hz
     
    exist in my code. Any suggestion?
    #7
    du00000001
    Just Some Member
    • Total Posts : 3065
    • Reward points : 0
    • Joined: 2016/05/03 13:52:42
    • Location: Germany
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/09 02:14:38 (permalink)
    0
    Might be there's a byte stuck in the RX buffer from a previous operation. Issuing dummy reads until the RX buffer is guaranteed to be empty (if I'm not completely wrong, this buffer is at least "double-buffered) would work around your current issue. Although the basic error would be "somewhere else", where you forgot to empty the buffer (most likely during some "write-only" operation: when it comes to SPI, "write-only" doesn't exist!

    PEBKAC / EBKAC / POBCAK / PICNIC (eventually see en.wikipedia.org)
    #8
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/09 02:33:04 (permalink)
    0
    May be you all right. 
    The full sequence is this:
     
    char ad_reset(void)
    {
    char i;
    char res=0;
    ARp=AudioBufferA;
    AD_init();
    TRIS_AD1;                                                               // AD1
    TRIS_AD2;
    TRISMISO1;
    TRISMISO2;
    TRISSCK1;
    TRISSCK2;
    AD1_DISABLE;
    AD2_DISABLE;
    AD1_ENABLE;
    SPI1BUF = 0;                                                         // send to make clocks
    while(!SPI1STATbits.SPIRBF);                                  // wait until the 8 clock
    AD1_DISABLE;
    AD2_ENABLE;
    SPI2BUF = 0;                                                       // send to make clocks
    Nop();
    Nop();
    Nop();
    Nop();
    while(!SPI2STATbits.SPIRBF);
    AD2_DISABLE;
    if_spixSend();                                                    // check 0xFF00
    if(*(ARp-2) == 0x00FF)res|=0b01;
    else res = 0;
    _SPI1IF=0;
    if(*(ARp-1) == 0x00FF)res|=0b10;
    else res |=0;
    for(i=0; i<3; i++){
    ARp=AudioBufferA;
    res=ad_reset();
    }
    return(res);
    }
     
    This part of the TLC 4545 initialization is quite nasty, because I was not able to get a stable initialization yet.
     
    #9
    Aussie Susan
    Super Member
    • Total Posts : 3618
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/09 19:26:03 (permalink)
    0
    Please use code tags around your code. Also you seem to be using a lot of macros that make it very hard to determine what is ACTUALLY happening. Even with comments the macro expansions can change the operation of the code very easily. Code such as "if_spixSend();" can expand to just about anything.
    Are you calling 'ad_reset()' recursively in the last few lines of your code? That looks like a guaranteed stack overflow to me!
    Why are there 'NOP();' calls between sending the dummy character to SPI2BUF and waiting for the exchange to complete?
    Susan
    #10
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/10 10:10:24 (permalink)
    0
    The related macro definitions here:
    #define TRIS_AD1 _TRISG9=0
    #define TRIS_AD2 _TRISB2=0
    #define TRISMISO1 _TRISF2=1
    #define TRISMISO2 _TRISG7=1
    #define TRISSCK1 _TRISF6=0
    #define TRISSCK2 _TRISG6=0
     
    #define AD1_CS _LATG9 // J7 con pin 7
    #define AD2_CS _LATB2 // J7 con pin 6
    #define AD1_ENABLE AD1_CS=0
    #define AD1_DISABLE AD1_CS=1
    #define AD2_ENABLE AD2_CS=0
    #define AD2_DISABLE AD2_CS=1

    #define MOSI1_PIN PORTFbits.RF3
    #define MISO1_PIN PORTFbits.RF2
    #define MSCK1_PIN PORTFbits.RF6
    #define MOSI2_PIN PORTGbits.RG8 // J7 con pin 5
    #define MISO2_PIN PORTGbits.RG7 // j7 con pin 4
    #define MSCK2_PIN PORTGbits.RG6 // j7 con pin 3
     
    The if_spixSend() is a function included my original topic. Yes the recursive coding really cause stack overflow I already change to:
    for(i=0; i<3; i++){
    ARp=AudioBufferA;
    res=ad_reset();
    }
    The whole reset suppose to fulfill TLC4545 reset requirement: to send max 8 clock within CS enabled and check wheather get back FF00 as an acknowledged reset cycle. 
    My result was: sometimes I read FF00 properly in the if_spixSend() cycle but most of the time not, while the oscilloscope clearly shows the FF00
    #11
    Aussie Susan
    Super Member
    • Total Posts : 3618
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/12 20:02:17 (permalink)
    0
    I assume the 'FF00' you mention is a 16-bit hex value (normally written as 0xFF00).
    The data sheet for the TLC5454 shows that the reset sequence is a single 8-bit exchange (with \CS\ being active for only those 8 SCK cycles) and then the next 16-bit exchange should result in the value 0xFF00 being received. In your 'ad_reset()' function you correctly initiate the 8-bit exchange (with the \CS\ control settings) but then you call your 'if_spixSend()' function that does 24-bit exchanges, not 16-bit.
    Finally, you are testing for 0x00FF and not 0xFF00!
    I think your logic is a bit muddled in this area which i why you may be getting into trouble.
    If I were you, I would:
    - create a function that handles the 8-bit SPI exchange, returning the read value and also taking into account error handling
    - create a single function that performs all of the initialisation, calling the above function as required and also handling the \CS\ bit
    - create a single function that reads the 24-bit ADC value.
    BTW - the code you show in post #11 that you say you have changed to is still including a recursive call to 'ad_reset()'!
    Susan
    #12
    u741
    Starting Member
    • Total Posts : 32
    • Reward points : 0
    • Joined: 2018/10/08 12:38:57
    • Location: 0
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/05/16 09:57:51 (permalink)
    0
    use a more modern MCP33131 from Microchip. 16-bit full-differential 1 MSps with super-simple SPI interface, instead of this 20 years old chip.
     
    #13
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/06/05 11:11:43 (permalink)
    0
    Yes, the  0x00FF was wrong because the TLC 4545 is big endian, but the mayor problem is the dspic33 errata!
    The SPI bus has a bug so I solve the problem using the Traxdata code for reading the SPI bus. Now is working correctly!
    I use the 24 bit cycle, because of tlc 4545 require for data conversion cycle.
    #14
    Aussie Susan
    Super Member
    • Total Posts : 3618
    • Reward points : 0
    • Joined: 2008/08/18 22:20:40
    • Location: Melbourne, Australia
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/06/05 20:19:00 (permalink)
    0
    The terms 'big-endian' and 'little-endian' are normally used to refer to how values are stored in the various internal registers/memory cells.
    With SPI value exchanges, the terms 'MSB first' and "LSB first' are used. Because the exchanges are on a bit-by-bit basis, the SPI exchange does not care how the values are interpreted at each end, only whether the first bit received is the MSB or LSB (etc.) and this is clearly shown in the data sheet.
    Looking at the SPI section of the errata, I must admit I can't see how that relates to your problem. In the code you have posted earlier, you always seen to wait for SPIRBF to be set before you read the received value and I would expect that. In the code in your attachment, you still seem to do that but have added in while loops waiting for SPITBF to be clear.
    The Errata is all about how you should wait one SPI clock before writing to the SPIBUF after the SPITBF is cleared. I don't see how adding in tests of a bit that is known to 'have issues' solves your problem. Also, clearing the SPIROV bit after each test of the SPITBF, is NOT necessarily waiting for an SPI clock - it is providing some delay but one that is tied to the system clock, not the SPI clock (although you do have a 4:1 prescaler setting for the SPI clock).
    Susan
    #15
    antal_peter
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2013/10/27 00:08:03
    • Location: Hungary
    • Status: offline
    Re: Using 2 SPI bus with TLC4545 2019/06/24 09:34:31 (permalink)
    0
    Hi Susan!
    First of all thanks for your help! Finally the TLC4545 chip working. The mayor problem was the byte order. The da converter was driven by word organized audio dma. So it was little endian byte order, because dsPIC is little endian. The TLC4545 reading I wrote was byte wide reading and the TLC4545 is Big endian, so the reading routine must be byte 1, byte 0, byte 3 and byte 2 for TDA1543 stereo D/A!
    #16
    Jump to:
    © 2019 APG vNext Commercial Version 4.5