Because of the Thanksgiving holiday in the U.S., TI E2E™ design support forum responses may be delayed from November 25 through December 2. Thank you for your patience.

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.

LP5890: CCSI Communication

Part Number: LP5890

Hi TI Team,

I was wondering if I could be sent the slides on the CCSI communication protocol that is used to control the LP5890. I would also like to know if the protocol would be possible to implement on an ST Nucleo-G071RB using the SPI interface.

  • Hi Evan,

    1. Sorry but what slides do you refer to? Please check [Q4] from this [FAQ] for some tips on CCSI. 
    2. CCSI can be implemented on the ST device you mentioned. You can refer to our sample code (check [Q2] from the above [FAQ]). You can check MSP430 version sample code (link: LP5890EVM-SW-F5529) where we use SPI and another GPIO pin to simulate CCSI.

    Best Regards,

    Steven

  • Hi Steven,

    Thanks for the feedback. I had seen someone else from TI refer to slides on CCSI in another form post here. Not sure if those exist anymore. I have some further questions on setting up the CCSI protocol on the ST board.

    1. How are the timers set up? Below is the code for setting up the timers in the sample code you referenced. I am unfamiliar with the MSP430, so I am wondering how this translates to ST. If I'm understanding correctly, the TA2.1 timer here is being set up to be the SPI clock, and TA0 is being used along with an interrupt in main.c to control the frame rate. I think my main question is how do the output modes (OUTMOD_2, OUTMOD_0) translate to the setup of an ST Timer? Also, what does the comment on line 4 mean (First trial for LP589x to increase SCLK to 12MHz), I thought since there was no clock division applied we would be running at 24MHz?

     

    void timerInitial()
    {
        TA2CTL |= TASSEL_2 + MC_0; //select SMCLK clock source, select /1 =24MHz, divider, select stop mode
        // First trial for LP589x to increase SCLK to 12 MHz
        TA2CCTL1 |= OUTMOD_2; //TA2.1 select toggle/reset mode//OUTMOD_2
    #ifdef TLC698X
        TA2CCR0 = 3;
        TA2CCR1 = 2;
    #endif
    #ifdef LP589X
        TA2CCR0 = 1;
        TA2CCR1 = 1;
    #endif
    
        P2DIR |= BIT4; //P2.4 set as output
        P2SEL |= BIT4;//P2.4 -> TA2.1
        TA2CTL |= MC_1; //select up mode to start timer
    
        // Timer 0 setup for frame rate control
        TA0CTL = TASSEL__SMCLK + ID_2 + MC_0; //select SMCLK clock source, select /4 = 6MHz, divider, select stop mode
        TA0CCTL0 = OUTMOD_0;
        TA0CCR0 = FRAME_PERIOD - 1;
        TA0EX0 = TAIDEX_5; // Select /6 --> 1MHz
        TA0CTL |= MC_1; //select up mode to start timer
        TA0CCTL0 |= CCIE; //enable TA0CCR1 CCIFG interrupt
    }

    Here is my current setup of one of the two ST timers, what I believe is to be analogous to TA2.1. This micro has the clock setup to run at 64MHz, so a clock division of 2 would bring it down to 32MHz which meets the requirement of SCLK on the LP5890 (max of 50MHz). The one thing I'm not sure about is the selection of the MasterOutputTrigger and the OCMode and if what I selected would work or not.

    htim2.Instance = TIM2;
      htim2.Init.Prescaler = 0;
      htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim2.Init.Period = 1;
      htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV2;
      htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
      {
        Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
      {
        Error_Handler();
      }
      if (HAL_TIM_OC_Init(&htim2) != HAL_OK)
      {
        Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
      {
        Error_Handler();
      }
      sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
      sConfigOC.Pulse = 0;
      sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
      sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
      if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
      {
        Error_Handler();
      }

    2. Is the actual SCLK for SPI that is set up just ignored entirely?

    3. How do we know the SOMI and SIMO channels are synchronous with the timer output? What's the relationship between the two? In the timer initialize code above, it looks like the TA2.1 is not having a clock division applied, so it is 24MHz. When looking at the SPI initialization function below however, the UCBxBR0 is set to 2, indicating that the SPI is running at half the frequency, 12MHz.

    void spiInitial()
    {
    
        UCB0CTL1 |= UCSWRST; //USCI rest software
        UCB0CTL0 |= UCCKPL + UCMSB + UCMST;//UCCKPH = 0, UCCKPL = 1;
        UCB0CTL1 |= UCSSEL__SMCLK ; //UCLK = SMCLK = 24MHz
        //UCB0BR0 = 2;
    #ifdef TLC698X
        UCB0BR0 = 2;//fBitClock = 24/2 = 12MHz --> With double edge this means SCLK is 6 MHz
    #endif
    #ifdef LP589X
        UCB0BR0 = 2;//fBitClock = 24/2 = 12MHz --> With rising-edge this means SCLK is 12 MHz
    #endif
        UCB0BR1 = 0;
        P3DIR |= BIT0 + BIT2; //P3.0 -> SIMO, P3.2 -> SPICLK;
        P3DIR &= ~ BIT1; //P3.1 -> SOMI;
        P3SEL |= BIT0 + BIT1 + BIT2;
        UCB0CTL0 &= ~UC7BIT; //8-bit character length
        UCB0CTL1 &= ~UCSWRST; //USCI rest released for operation
    }

    Thank you in advance for answering my questions. Let me know if you need any more information in order to answer these.

  • Hi Evan,

    Do you refer to this thread: LP5890: Lp5890 CCSI communication - Power management forum - Power management - TI E2E support forums?

    Meanwhile, I will find an expert in our team and let him / her answer your software-related question.

    Best Regards,

    Steven

  • Yes, that was the thread that I tried to link to where they referenced the slides.

  • Hi Evan,

    Got it. I will talk with Monet about that.

    BR, Steven

  • Hi Evan,

    I send you a friendship request on this E2E forum with my email attached. Please send an email to me and I will send you the CCSI slides.

    Best Regards,

    Steven

  • Hi Evan,

    When using an ST MCU, I would recommend you check to use the SAI peripheral (or I2S).

    1. The MSP430 code is relying on the clock system structure where the CPI, Timer, and the SPI peripheral get the same system clock.
      1. TA2 is indeed used to generate the continuous clock. The output set by the mode is toggling every 2 clock cycles. Therefore, the clock becomes half of the system clock.
      2. The comment on line 4 can be ignored. In older versions of the code, the continuous clock was running at a lower frequency.
      3. TA0 is indeed the timer to generate an interrupt every frame period to start the transmission of the VSYNC command.
    2. The output of the SPI interface is unused. However, the clock still needs to be setup to generate the data output at the same frequency as the Timer.
    3. We start the DMA based on the timer count value and therefore the SPI data is shifted out at the same time as the falling edge of the Timer clock output.
  • Hi Ben,

    Thanks for the reply, I am starting to make sense of how this is working. Some other questions I have as I have been trying to implement this on my ST board are:

    1. Why are you suggesting I use I2S over SPI?

    2. I understand the DMA is triggered by the TA2 timer count, but what is the point of storing DMA0CTL in dma0ctl_val in the following code?

    void dmaTransfer(unsigned int dmaTxSize, unsigned int dmaRxSize, unsigned int checkResponse)
    {
        uint16_t idx = 0;
        uint16_t startLoop = 0;
        uint16_t endLoop = 0;
        volatile uint16_t timer_val = 0;
        volatile uint16_t dma0ctl_val = 0;
    
        if(firstTransfer == FALSE){
            while(!(DMA0CTL&DMAIFG)); //Wait until send all command bytes
            DMA0CTL &= ~(DMAEN + DMAIFG);//disable DMA0
        }
        else
            firstTransfer = FALSE;
        
        if(checkResponse==TRUE) {
            // Ensure that rest of transmit data is all 0xFFFF
            if(dmaTxSize < dmaRxSize) {
                startLoop = (dmaTxSize >> 1) + (dmaTxSize & 0x1);
                endLoop = (dmaRxSize >> 1) + (dmaRxSize & 0x1);
                for(idx = startLoop; idx <= endLoop; idx++){
                    ledXmtBuffer[0][idx] = 0xFFFF;
                }
            }
            DMA0SZ = dmaRxSize;
            DMA1SZ = dmaRxSize;
        }
        else {
            DMA0SZ = dmaTxSize;
        }
    
        dma0ctl_val = DMA0CTL;
        dma0ctl_val |= DMAEN;
        timer_val = TA2R;
    
        while(timer_val > 0){
            timer_val--;
        }
    
    #ifdef LP589X
        __no_operation();
    #endif
    
        DMA0CTL = dma0ctl_val;
    
        if(checkResponse==TRUE)
        {
            DMA1CTL |= DMAEN; //enable Rx DMA
            while(!(DMA0CTL&DMAIFG)); //Wait until send all command bytes
            while(!(DMA1CTL&DMAIFG)); //Wait until receive all response byte
            DMA1CTL &= ~(DMAEN + DMAIFG); //disable DMA1
            DMA0CTL &= ~(DMAEN); //disable DMA0
        }
    }

    Thank you again for taking the time to answer these questions.

  • Hi Even,

    1. Serial audio interfaces such as SAI and I2S have a continuous clock where the data is automatically aligned to that clock. I have not used those interfaces myself as the MSP430 MCU does not have them.
    2. First reading and preparing the register value helped to control the number of CPU cycles better. Actually, it would have even been better to write this portion of code in assembly and not allowing any code optimizations on that section for full control of CPU cycles.