Control SPI SS_CTL for single burst operation.

cancel
Showing results for 
Search instead for 
Did you mean: 

Control SPI SS_CTL for single burst operation.

1,975 Views
CHOIHYONGEUN
Contributor I

Hi, all.

Please understand that my english is not good enough.

I'm currently working with the i.MX53 EVK.

I'm having some trouble with the ECSPI.

My SPI device requires the CS/SS pin to be held low for the length of the SPI burst.

I thought that it is not a proper way to change bits_per_word value,

because normal burst read size is more than 32-bits.

I found a way to control SS waveform in ECSPI config register.

So, i comment out the code to set ss_ctl bit, as shown below.

/* mxc_spi.c */

void mxc_spi_chipselect(struct spi_device *spi, int is_active)

{

  .....

  if (spi_ver_def == &spi_ver_2_3) {

    .....

    if (spi->mode & SPI_CS_HIGH) {

      config_reg |=

        ((((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

          spi_ver_def->mode_mask) | cs_value) << spi_ver_def->ss_pol_shift);

    } else

      config_reg |=

        ((~((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

          spi_ver_def->mode_mask) & cs_value) << spi_ver_def->ss_pol_shift);

#if 0 /* single burst transfer */

    config_reg |=

      (((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

        spi_ver_def->mode_mask) << spi_ver_def->ss_ctrl_shift);

#endif

    __raw_writel(0, master_drv_data->base + MXC_CSPICTRL);

    __raw_writel(ctrl_reg, master_drv_data->base + MXC_CSPICTRL);

    __raw_writel(config_reg, MXC_CSPICONFIG + master_drv_data->ctrl_addr);

    .....

 

This is the code for SPI burst read in my SPI device driver. (master mode, bits_per_word:8)

/* my_spi.c */

void my_spi_read_burst(unsigned char reg, unsigned char *buf, int size)

{

  int ret;

  u8 tmp_buf[2];

  struct spi_message msg;

  struct spi_transfer msg_xfer;

 

  spi_message_init(&msg);

  memset(&msg_xfer, 0, sizeof(msg_xfer));

 

  msg_xfer.tx_buf = tmp_buf;

  msg_xfer.len = 2;

 

  tmp_buf[0] = MY_SPI_CHIP_ADDR;

  tmp_buf[1] = reg;

  spi_message_add_tail(&msg_xfer, &msg);


  ret = spi_sync(my_spi_ptr->spi_ptr, &msg);

  if (ret)

    printk("spi_sync error\n");

 

  spi_message_init(&msg);

  memset(&msg_xfer, 0, sizeof(msg_xfer));

 

  msg_xfer.tx_buf = buf;

  msg_xfer.rx_buf = buf;

  msg_xfer.len = size;

 

  buf[0] = (MY_SPI_CHIP_ADDR | 0x1);

  spi_message_add_tail(&msg_xfer, &msg);

 

  ret = spi_sync(my_spi_ptr->spi_ptr, &msg);

  if (ret)

    printk("spi_sync error\n");}

 

Unfortunately it does not work. Am I missing something?

Read operation is infinitely waiting for transfer completion in mxc_spi_transfer function.

The reason is as shown below.

static irqreturn_t mxc_spi_isr(int irq, void *dev_id)

{

  struct mxc_spi *master_drv_data = dev_id;

  irqreturn_t ret = IRQ_NONE;

  unsigned int status;

  int fifo_size;

  unsigned int pass_counter;

 

  fifo_size = master_drv_data->spi_ver_def->fifo_size;

  pass_counter = fifo_size;

 

  /* Read the interrupt status register to determine the source */

  status = __raw_readl(master_drv_data->stat_addr);

  do {

    u32 rx_tmp =  __raw_readl(master_drv_data->base + MXC_CSPIRXDATA);

 

    if (master_drv_data->transfer.rx_buf)

      master_drv_data->transfer.rx_get(master_drv_data, rx_tmp);

 

    (master_drv_data->transfer.count)--;

    (master_drv_data->transfer.rx_count)--;  <-------- rx_count is 386

    ret = IRQ_HANDLED;

    if (pass_counter-- == 0) {

      break;

    }

    status = __raw_readl(master_drv_data->stat_addr);  <-------- status is 0x80 (RR is 0),                                                                                  exit a while loop immediately

  } while (status &

             (1 << (MXC_CSPISTAT_RR + master_drv_data->spi_ver_def->int_status_dif)));

 

  if (master_drv_data->transfer.rx_count)

    return ret;  <-------- rx_count is 385, return from the function and no more interrupt.

 

  if (master_drv_data->transfer.count) {

    if (master_drv_data->transfer.tx_buf) {

      u32 count = (master_drv_data->transfer.count > fifo_size) ?

                      fifo_size : master_drv_data->transfer.count;

      master_drv_data->transfer.rx_count = count;

      spi_put_tx_data(master_drv_data->base, count, master_drv_data);

    }

  } else {

    complete(&master_drv_data->xfer_done);  <-------- Never reached

  }

  return ret;

}

Please advise me.

Thanks.

Tags (1)
0 Kudos
4 Replies

612 Views
Yuri
NXP TechSupport
NXP TechSupport

Hello,

   It is possible to get operations as shown on the Figure 24-8 (SPI Burst While SS_CTL[3:0] is Clear)

of the i.MX53 RM (Rev. 2, 6/2012), but the description under the figure is not fully correct. 

"The maximum length of a single SPI burst is defined in the BURST LENGTH field of the ECSPI_CONREG

control register". Really the maximum length of the single SPI burst is defined by FIFO. When FIFO is

underflowed (empty) the SS is negated.  ECSPIx_PERIODREG may be used to setup delays between

SPI transfers.

Regards,

Yuri.

0 Kudos

612 Views
jeffreycoffman
Contributor III

Did you ever figure this out?  I have the same issue on an i.MX6 quad, I set SS_CTL for single burst and clear SMC as described in the data sheet and still see the CS toggling between bursts.

0 Kudos

612 Views
yektaayduk
Contributor II

My Spi devices require also no toggling between bursts. I made some changes in mxc_spi.c for mx53 .Now my device accept opcode and reister address and replay with regset value.But somehow the spi_write_then_read function doesnt get the same value ,I observe on the osciloscope ?

Code :

       //--------------------- change begin-----------------

        if (spi->single_CS == 0)

        {

        ctrl_reg &= ~(spi_ver_def->smc) ;

        config_reg &= ~((((1 << (spi->chip_select & MXC_CSPICTRL_CSMASK)) &

                          spi_ver_def->mode_mask) << spi_ver_def->ss_ctrl_shift));

        master_drv_data->usedma =0 ;

        }

        ctrl_reg |= (0x1F << 20);// burstlen =32bits <= bit =CR[31:20]

        //------------------------change end------------------------------------------------------

        __raw_writel(ctrl_reg, master_drv_data->base + MXC_CSPICTRL);

        __raw_writel(config_reg,MXC_CSPICONFIG + master_drv_data->ctrl_addr);

Added waveform:

But normally I should write  txbuf[0]=0x13 ,txbuf[1]=0x1d   expected result from device =0x81

But it works when I put txbuf0= dummy=0x0 txbuf1=dummy=0x0 txbuf2=0x1d txbuf3=0x13  32 bits into buffer .

I think rxFIFO capturing is also starts end ends with cs edges ?

0 Kudos

612 Views
jeffreycoffman
Contributor III

I ran into this late last week after I figured out how to correctly set BURST_LENGTH.  Here is my understanding so far.  It appears from the data sheet (which contains a very round about description) and what I have observed, that burst length 31:20 allows you to only control the width in bits of the first word, after that any additional words specified are 32 bits in length. It allows you to specify a transfer of any arbitrary bit length in a single burst from 1 to 4096 bits.  The control over the first word allows you to handle cases where your entire burst length is not a multiple of 32 bit words.

So you have defined the first word to be 32 bits,

ctrl_reg |= (0x1F << 20)    ->  n = BL + 1, 32 = 0x1F+1


With no additional words [31:25] cleared.


So now the controller is going to shift out all 32 bits because that is what you told it todo.  That's why you needed to populated your txbuf with 4 bytes.

For my device I want to send a 1 byte command and then get back 4 bytes.

so I set the first word to be 8 bits  ctrl_reg |= (7<< 20)


then specify the remaining 32 bit words in [31:25].


ctrl_reg |= (1 << 25)

As for RXIFIFO; since it is now one continuous transfer (in regard to cs), it doesn't appear to advance the RX fifo until all 32 bits are shifted in.  If you look at the driver spi_imx.c you'll see that it uses a different routine for reading rx fifo based on bpw.  So if your set up for 8 bpw then its not going to populate your buffer correctly.  Temporarily you can set it up to use the spi_imx_buf_rx_u32 for your example (being careful to make sure your buffer is in increments of 32 bit words).  For a more permanent solution the driver needs to take this into account when cs_change = 0, and make sure it properly maps the 32 bit values from each rxfifo read into the transfer based on whatever bpw the spi transaction has specified.

Hope this explains what your seeing.

0 Kudos