6 Replies Latest reply on Nov 14, 2016 10:33 AM by SergeyK

    Quark D2000 - Master SPI

    Harry07

      Hello!

       

      I'm needing help to make SPI work. I have readed and used the functions specified in "qm_spi.h", to implement  reading and writing to ADE7758 chip (with a level shifter between that is working fine).

       

      After writing and then reading a register I always get the maximun value for that register, for example If I write to a 8bits register, when I read I get 0XFF. Here is how I implemented SPI.

       

      // ADE7758_driver.c

       

      ....

      ....

      void set_spi_basic_conf(){

       

        cfg_spi.bus_mode = modo_1;

        cfg_spi.clk_divider = SPIclock_div16;

      }

       

      void spi_conf(const qm_spi_config_t *const cfg){

       

        int ret __attribute__((unused));

        // --> Se configura: tamaño frame, SCK, bus mode

        ret = qm_spi_set_config(QM_SPI_MST_0, cfg);

        QM_ASSERT(0 == ret);

        // --> Selcción de Chip enable

        ret = qm_spi_slave_select(QM_SPI_MST_0, QM_SPI_SS_0);

        QM_ASSERT(0 == ret);

      }

       

      /* void write8bits(int8_t reg, uint8_t data)

      *

      * int8_t reg: Registro que se desea escribir,

      *

      * uint8_t data: datos que se desean escribir en reg

      *

      * */

      void write8bits(uint8_t reg, uint8_t data){

       

        // Se guarda la direccion del registro a ser escrito, colocando su MSB en 1 para indicar escritura

        // al ADE7758.

        uint8_t data_aux = REG_WRITE(reg);

       

        //--> Guardo configuracion SPI en registro configuracion

        cfg_spi.frame_size = frame16bits; //1er Byte indica a que registro /2do Byte los datos

        cfg_spi.transfer_mode = tranf_mode_tx;

        //--> Configuro SPI

        spi_conf(&cfg_spi);

        // --> Guardo datos en buffer_TX

        buffer_TX.tx = &data_aux;

        buffer_TX.tx_len = 2;

        buffer_TX.rx_len = 0;

        // --> Consulto estado SPI

        qm_spi_get_status(QM_SPI_MST_0,&SPI_status);

        // --> Se envía datos de buffer_TX: En este paso se indica que el proceso es de escritura a reg.

        qm_spi_transfer(QM_SPI_MST_0,&buffer_TX,&SPI_status);

        // --> Cargo datos para pasar al chip

        data_aux = data;

        // --> Guardo datos en buffer_TX

        buffer_TX.tx = &data_aux;

        // --> Consulto estado SPI

        qm_spi_get_status(QM_SPI_MST_0,&SPI_status);

        // --> Transmito datos para la escritura.

        qm_spi_transfer(QM_SPI_MST_0,&buffer_TX,&SPI_status);

       

      }

      ...

      ...

       

      //main.c

       

      int main(void)

      {

        //Variables

        uint8_t  reg_0;

        uint16_t reg_1;

        uint32_t reg_3;

       

       

        // Iniciamos configuracion basica de SPI (SCK y Bus_mode)

        set_spi_basic_conf();

       

       

        // --> Prueba de write/read 8-bits

        reg_0 = 0x04;

        write8bits(OPMODE, reg_0);

        reg_0 = 0x00;

        reg_0 = read8bits(OPMODE);

        QM_PRINTF("OPMODE: /n");

        QM_PRINTF("x% \n",reg_0);

        // --> Prueba de write/read 16-bits

        reg_1 = 0x00C;

        write16bits(LINECYC, reg_1);

        reg_1 = 0x0000;

        reg_1 = read16bits(LINECYC);

        QM_PRINTF("LINECYC: /n");

        QM_PRINTF("x% \n",reg_1);

        // --> Prueba de write/read de 24-bits

        reg_3 = 0x00000;

        reg_3 |=(1<<LENERGY);

        write24bits(MASK,reg_3);

        reg_3 = 0x00000;

        reg_3 = read24bits(MASK);

        QM_PRINTF("MASK: /n");

        QM_PRINTF("x% \n",reg_3);

       

        return 0;

      }

       

      I will apreciate if anyone could give me a hand with it.

        • 1. Re: Quark D2000 - Master SPI
          J.Pacheco

          Hi Harry07,

           

           

          Thanks for your interest in the Intel Quark Platform.

           

          Could you please include in your code the libraries you are using and could you please use an oscilloscope in order to see if the MISO, MOSI and CS is showing an accurate behavior. Thanks in advance, I hope you have a nice day.

           

          Best Regards, 

          -Jose

          • 2. Re: Quark D2000 - Master SPI
            Lockdog
            1 of 1 people found this helpful
            • 3. Re: Quark D2000 - Master SPI
              J.Pacheco

              Hi Harry07,

               

               

              First thanks to Lockdog for sharing the example above. Now were you able to try my last suggestion? Or the code provided by Lockdog? Please let me know in order to help you.

               

               

              I will be waiting for your reply, have a nice day.

               

               

              Regards, 

              -Jose

              • 4. Re: Quark D2000 - Master SPI
                SergeyK

                A few suggestions:

                1. Make sure that pin multiplexers are configured to SPI mode. At least the following pins. The slave select pin might be different depending on your circuit:

                qm_pmux_select(QM_PIN_ID_0, QM_PMUX_FN_2);*/  /* SS0 */

                qm_pmux_select(QM_PIN_ID_16, QM_PMUX_FN_2); /* SCK */

                qm_pmux_select(QM_PIN_ID_17, QM_PMUX_FN_2); /* TXD */

                qm_pmux_select(QM_PIN_ID_18, QM_PMUX_FN_2); /* RXD */

                qm_pmux_input_en(QM_PIN_ID_18, true);       /* RXD input */

                 

                2. From a quick glance at ADE7758 datasheet, it appears that it uses 8-bit frames (not 16-bit). Set the SPI controller configuration accordingly:

                cfg_spi.frame_size = QM_SPI_FRAME_SIZE_8_BIT;

                 

                3. SPI slave devices require sending "dummy" bytes in order to receive data. So for example, the transaction to read a 8-bit value might look like:

                SPI MOSI: <command_byte> <dummy_byte>

                SPI MISO: <status_byte> <value>

                Note that this is all happening as a single "transaction" where the slave select (SSx) kept active the whole time. Just sending the command byte, and then reading the value byte won't work, because slave select will be deactivated after sending the command byte, and the SPI slave would not "understand" the read request. Generally I'd suggest setting up the SPI controller to QM_SPI_TMOD_TX_RX mode:

                cfg_spi.transfer_mode = QM_SPI_TMOD_TX_RX;

                 

                The code snippet to read a 8-bit register might look like:

                 

                uint8_t read_register (uint8_t register_addr)

                {

                  qm_spi_transfer_t spi_xfer;
                  qm_spi_status_t spi_status;

                  uint8_t tx_buf[2], rx_buf[2];

                 

                  spi_xfer.tx = tx_buf;
                  spi_xfer.tx_len = sizeof(tx_buf);
                  spi_xfer.rx = rx_buf;
                  spi_xfer.rx_len = sizeof(rx_buf);

                 

                  tx_buf[0] = register_address;


                  qm_spi_transfer(QM_SPI_MST_0, &spi_xfer, &spi_status);

                 

                  /* note, returning the second byte of the rx_buffer - it contains the read value */

                  return rx_buf[1];

                }

                 

                The code snippet to write a 8-bit register:

                void write_register (uint8_t register_addr, uint8_t vale)

                {

                  qm_spi_transfer_t spi_xfer;
                  qm_spi_status_t spi_status;

                  uint8_t tx_buf[2], rx_buf[2];

                 

                 

                  spi_xfer.tx = tx_buf;
                  spi_xfer.tx_len = sizeof(tx_buf);
                  spi_xfer.rx = rx_buf;
                  spi_xfer.rx_len = sizeof(rx_buf);

                 

                  tx_buf[0] = register_address;

                  tx_buf[1] = value;

                 

                  qm_spi_transfer(QM_SPI_MST_0, &spi_xfer, &spi_status);

                 

                  return;

                }

                 

                4. A word of warning: The DesignWare SPI controller used in the D2000 has the SPI queue of a 7 or so bytes. It will drop slave select after sending/receiving that number of bytes. As a workaround, if the application requires sending or receiving of more than 7 bytes, the slave select can be implemented in software using a GPIO pin.

                • 5. Re: Quark D2000 - Master SPI
                  Harry07

                  Thanks all for your advices!!

                   

                  I've been working on others things and couldn't progress with this staff. Today, I implemented SergeyK suggestions to my code, and noticed while debugging that dummy byte, when reading, is only send in QM_SPI_TMOD_RX mode, not in QM_SPI_TMOD_TX_RX. So, I finally decided to implement reading 8bits with the mode suggested by SergeyK but with buffers of size=1.

                   

                  Even I implement those changes to my code I didn't get it working properly. The result reported is always "255".....

                   

                  I'll try using a Oscilloscope to check that SPI signal are correct and comment to this post when I have new results.

                   

                  Thanks all again!

                  • 6. Re: Quark D2000 - Master SPI
                    SergeyK

                    Please make sure that slave select signal stays active during the whole transaction: sending the command/register address and sending or receiving the data. In my example the size is specifically set to the length of the entire transaction (2 bytes). This of course will depend on the particular device and transaction...

                    If that ADE7758 is the only device connected to the SPI bus, you can try connecting the /CS to the ground...