SPI read returns 'JCB'

Comments

4 comments

  • Engineering Support
    Community moderator

    Hi Randall,

    Could you please provide your wiring diagram or schematic you are using to connect to the display? As well as the code you used to communicate with the display.

    0
  • Randall Moon

    0
  • Randall Moon

    #include "em_gpio.h"
    #include "app_timer.h"
    #include <stdint.h>
    #include "sl_spidrv_instances.h"
    #include "app_assert.h"
    #include "FT81x_defines.h"

    void FT81x_PD_init(void);
    uint8_t FT81x_rd8(const uint32_t address);
    uint32_t FT81x_rd32(const uint32_t address);
    void FT81x_wr8(uint32_t address, uint8_t data);
    void FT81x_wr16(const uint32_t address, const uint16_t data);
    void FT81x_wr32(const uint32_t address, const uint32_t data);

    uint32_t FT81x_rd_test(void);

    void ft81x_power_on(void);
    void FT81x_host_command(const uint32_t cmd);
    uint32_t FT81x_readID(void);
    void NHD_config(void);
    uint32_t FT81x_readID(void);
    void wr_DL_1(void);

    // i3_timer used for test, Start, 1, or stop, 0, periodic timer
    static app_timer_t test_timer;

    static void test_timer_cb(app_timer_t *timer, void *data);

    // Start or stop periodic timer
    void test_timer_start_stop(uint8_t start_stop);


    uint16_t sec_count = 0;

    /***************************************************************************//**
     * Initialize application.
     ******************************************************************************/
    void app_init(void)
    {
      volatile uint32_t chip_id = 0xffffffff;
      volatile uint8_t reg_id = 0xffffffff;

      sl_spidrv_init_instances();

      FT81x_PD_init();                        // set port C pin 6 to push pull output
      sl_sleeptimer_delay_millisecond(1000);
      ft81x_power_on();                       // cycle power down pin
      sl_sleeptimer_delay_millisecond(2000);

      //test_timer_start_stop(1);

      FT81x_host_command(ACTIVE);
      sl_sleeptimer_delay_millisecond(9000);

      reg_id = FT81x_rd8(REG_ID);
      sl_sleeptimer_delay_millisecond(2000);

      chip_id = FT81x_readID();
      sl_sleeptimer_delay_millisecond(2000);

      //chip_id = FT81x_readID();
      sl_sleeptimer_delay_millisecond(2000);

      NHD_config();
      sl_sleeptimer_delay_millisecond(2000);

      //chip_id = FT81x_readID();
      sl_sleeptimer_delay_millisecond(1000);

      FT81x_rd_test();
      sl_sleeptimer_delay_millisecond(2000);


    }

    /***************************************************************************//**
     * App ticking function.
     ******************************************************************************/
    void app_process_action(void)
    {
    }


    uint8_t FT81x_rd8(const uint32_t address)
    {
      //uint32_t cmd = address;
      volatile uint32_t cmd = address | READ;
      volatile uint8_t tx_data[4];
      //uint8_t rx_data = 0xff;
      uint8_t rx_data[4];

      tx_data[0] = cmd >> 16;
      tx_data[1] = cmd >> 8;
      tx_data[2] = cmd & 0xff;
      tx_data[3] = 0x00;
    /*
      // send the address
      SPIDRV_MTransmitB(sl_spidrv_TFT_handle, &tx_data, 4);
      // receive the data
      SPIDRV_MReceiveB(sl_spidrv_TFT_handle, &rx_data, 1);
    */
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[0], &rx_data[0]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[1], &rx_data[1]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[2], &rx_data[2]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[3], &rx_data[3]);

      return rx_data[0];
    }


    uint16_t FT81x_rd16(const uint32_t address)
    {
      Ecode_t success;
      //uint32_t cmd = address;
      volatile uint32_t cmd = address | READ;
      uint8_t tx_data[4];
      //uint8_t rx_data = 0xff;
      uint8_t rx_data[8];
      volatile uint16_t result = 0x0000;

      rx_data[2] = 0xffffffff;

      tx_data[0] = cmd >> 16;
      tx_data[1] = cmd >> 8;
      tx_data[2] = cmd;
      tx_data[3] = 0x00;

     

      // send the address
      //SPIDRV_MTransmitB(sl_spidrv_TFT_handle, &tx_data, 4);
      SPIDRV_MTransferB(sl_spidrv_TFT_handle, &tx_data, &rx_data, 4);

      // receive the data
      //SPIDRV_MReceiveB(sl_spidrv_TFT_handle, &rx_data, 2);
      //SPIDRV_MTransferB(sl_spidrv_TFT_handle, &tx_data[3], &rx_data, 2);

      success = SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[3], &rx_data[4]);
      success = SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[3], &rx_data[5]);
      success = SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[3], &rx_data[6]);
      success = SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_data[3], &rx_data[7]);

      result = result | rx_data[0] | (rx_data[1] << 8);
      return result;
    }


    /*
     * read 4 bytes from specified address
     *
     */
    uint32_t FT81x_rd32(const uint32_t address)
    {
      volatile uint32_t cmd = address | READ;
      Ecode_t success;
      uint8_t rx_data[4];
      uint8_t tx_data[4];
      volatile uint32_t result;

      // wait for ready
      tx_data[0] = (cmd>>16);
      //SPIDRV_MTransmitB(sl_spidrv_usart_TFTspi_handle, &tx_buff[0], 1);
      tx_data[1] = (cmd>>8);
      //SPIDRV_MTransmitB(sl_spidrv_usart_TFTspi_handle, &tx_buff[1], 1);
      tx_data[2] = (cmd & 0xff);
      //SPIDRV_MTransmitB(sl_spidrv_usart_TFTspi_handle, &tx_buff[2], 1);
      tx_data[3] = 0x00;       // dummy byte
      //SPIDRV_MTransmitB(sl_spidrv_usart_TFTspi_handle, &tx_buff[3], 1);

      rx_data[0] = 0x00;       // read byte
      rx_data[1] = 0x00;       // read byte
      rx_data[2] = 0x00;       // read byte
      rx_data[3] = 0x00;       // read byte

      // send the address
      //success = SPIDRV_MTransmitB(sl_spidrv_usart_TFTspi_handle, &tx_buff, 4);

      // receive the data
      //success = SPIDRV_MReceiveB(sl_spidrv_usart_TFTspi_handle, &rx_data, 4);

    //  GPIO_PinOutClear(gpioPortC, 3);     // CS low
      success = SPIDRV_MTransferB(sl_spidrv_TFT_handle, &tx_data, &rx_data, 4);
    //  GPIO_PinOutSet(gpioPortC, 3);     // CS high

      if(!success) {
          //result = result | rx_data[0] << 24 | rx_data[1] << 16 | rx_data[2] << 8 | rx_data[3];
          result = result | rx_data[0] | (rx_data[1] << 8) | (rx_data[2] << 16) | (rx_data[3] << 24);
          return result;
      }
      else {
          return 0;
      }
    }


    /*
     * write 8 bit value to TFT
     */
    //Ecode_t TFT_wr8(uint32_t offset, uint8_t data)
    void FT81x_wr8(const uint32_t address, uint8_t data)
    {
      //Ecode_t success;
      uint32_t cmd = address | WRITE;
      uint8_t tx_buff[4];

      tx_buff[0] = cmd >> 16;
      tx_buff[1] = cmd >> 8;
      tx_buff[2] = cmd;
      tx_buff[3] = data;

      SPIDRV_MTransmitB(sl_spidrv_TFT_handle, &tx_buff, 4);
      //return success;
    }


    /*
     * write 16 bits of data to FT81x address
     *
     * example:    FT81x_wr16(FT81x_REG_VSIZE, 240);
     */
    void FT81x_wr16(const uint32_t address, uint16_t data)
    {
      //Ecode_t success;
      uint32_t cmd = address | WRITE;
      uint8_t tx_buff[5];
      uint8_t rx_buff[5];

      tx_buff[0] = cmd >> 16;
      tx_buff[1] = cmd >> 8;
      tx_buff[2] = cmd;
      tx_buff[3] = data;
      tx_buff[4] = data >> 8;

    //  SPIDRV_MTransmitB(sl_spidrv_TFT_handle, &tx_buff, 5);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_buff[0], &rx_buff[0]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_buff[1], &rx_buff[1]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_buff[2], &rx_buff[2]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_buff[3], &rx_buff[3]);
      SPIDRV_MTransferSingleItemB(sl_spidrv_TFT_handle, tx_buff[4], &rx_buff[4]);

      //return success;
      sl_sleeptimer_delay_millisecond(2000);
    }


    void FT81x_wr32(const uint32_t address, const uint32_t data)
    {
      uint32_t cmd = address | WRITE;
      //Ecode_t success;
      uint8_t tx_buff[7];

      tx_buff[0] = cmd>>16;
      tx_buff[1] = cmd>>8;
      tx_buff[2] = cmd;
      tx_buff[3] = data;
      tx_buff[4] = data>>8;
      tx_buff[5] = data>>16;
      tx_buff[6] = data>>24;

      // send the data
      SPIDRV_MTransmitB(sl_spidrv_TFT_handle, &tx_buff, 7);
    }


    /*************************************
     Start timer , 1 second periodic timer
     called from app_init
     *************************************/
    void test_timer_start_stop(uint8_t start_stop)
    {
      sl_status_t sc;

      if (start_stop) {
        // Start timer used for testing.
        sc = app_timer_start(&test_timer,
                             1 * 1000,
                             test_timer_cb,
                             NULL,
                             true);
        app_assert_status(sc);
        test_timer_cb(&test_timer, NULL);
      }
      // stop timer
      else {
        // Stop timer used for periodic indications.
        sc = app_timer_stop(&test_timer);
      }
    }

    /**************************************************************************//**
     * Timer callback
     * Called periodically to time periodic temperature measurements.
     *****************************************************************************/
    static void test_timer_cb(app_timer_t *timer, void *data)
    {
      (void)data;
      (void)timer;

     

      sec_count++;
    }


    void FT81x_PD_init(void)
    {
        GPIO_PinModeSet(gpioPortC, 6, gpioModePushPull, 0);
    }


    /*
     * power ON TFT
     * ref FT81x datasheet p. 37, 4.8.3 Power Modes
     *
     */
    void ft81x_power_on(void)
    {
      GPIO_PinOutClear(gpioPortC, 6);     // power down tft
      sl_sleeptimer_delay_millisecond(1000);
      GPIO_PinOutSet(gpioPortC, 6);       // power ON, sleep mode
      sl_sleeptimer_delay_millisecond(1000);

    }

    /*
     * host command
     * ref FT81x.pdf page 16, 4.1.5 Host Command
     * 3 byte command followed by dummy byte
     * prefix is b'01
     *
     */
    void FT81x_host_command(const uint32_t cmd)
    {
      uint8_t txbuff[3];
      uint8_t rxbuff[4];

      txbuff[0] = cmd >> 16;
      txbuff[1] = cmd >> 8;
      txbuff[2] = cmd;

      // wait for ready

      //SPIDRV_MTransmitB(sl_spidrv_TFT_handle, &rxbuff, 3);
      SPIDRV_MTransferB(sl_spidrv_TFT_handle, &txbuff, &rxbuff, 3);
    }

    /*
     * read chip ID from address 0xC0000 - 0xC0003
     *
     */
    uint32_t FT81x_readID(void)
    {
      uint32_t ret_val = 0x00000000;

      ret_val = FT81x_rd32(0xC0000);

      return ret_val;
    }

    /*
     * Configure display registers - for NHD part
     * NHD part # NHD-3.5-320240FT-SCXP-T
     *
     */
    void NHD_config(void)
    {
      // horizontal timing
      FT81x_wr16(REG_HSIZE, 320);
      FT81x_wr16(REG_HCYCLE, 408);
      FT81x_wr16(REG_HOFFSET, 70);
      FT81x_wr16(REG_HSYNC0, 0);
      FT81x_wr16(REG_HSYNC1, 10);

      // vertical timing
      FT81x_wr16(REG_VSIZE, 240);
      FT81x_wr16(REG_VCYCLE, 263);
      FT81x_wr16(REG_VOFFSET, 13);
      FT81x_wr16(REG_VSYNC0, 0);
      FT81x_wr16(REG_VSYNC1, 2);

      // clock settings
      FT81x_wr16(REG_PCLK,8);//after this display is visible on the LCD      //wr8
      FT81x_wr8(REG_SWIZZLE, 2);      //wr8
      FT81x_wr8(REG_PCLK_POL, 0);      //wr8
      FT81x_wr8(REG_CSPREAD, 0);      //wr8

    }

    /*
     * write first display list
     *
     */
    void wr_DL_1(void)
    {
      FT81x_wr32(RAM_DL+0, 0x02000000);  // set clear color
      FT81x_wr32(RAM_DL+4, 0x26000003);            // clear screen
      FT81x_wr32(RAM_DL+8,0x00000000);
      FT81x_wr16(REG_DLSWAP,DLSWAP_FRAME);          //display list swap      //wr8
      FT81x_wr16(REG_GPIO_DIR,0x80 | FT81x_rd8(REG_GPIO_DIR));      //wr8
      FT81x_wr16(REG_GPIO,0x080 | FT81x_rd8(REG_GPIO));//enable display bit      //wr8
      FT81x_wr16(REG_PCLK,8);//after this display is visible on the LCD      //wr8
    }


    /*
     * read some registers for test
     *
     */
    uint32_t FT81x_rd_test(void)
    {
      volatile uint16_t hsize = 0x00000000;
      volatile uint16_t hcycle = 0x00000000;
      volatile uint16_t hoffset = 0x00000000;
      volatile uint16_t hsync0 = 0x00000000;
      volatile uint16_t hsync1 = 0x00000000;

      hsize = FT81x_rd16(REG_HSIZE);
      hcycle = FT81x_rd16(REG_HCYCLE);
      hoffset = FT81x_rd16(REG_HOFFSET);
      hsync0 = FT81x_rd16(REG_HSYNC0);
      hsync1 = FT81x_rd16(REG_HSYNC1);

      return hsize;
    }

    0
  • Engineering Support
    Community moderator

    Hi Randall,

    The wiring diagram seems correct to me.

    Could you confirm if your SPI timing characteristics and setup is configured properly based on the datasheet?

    I would also check if the structure of the data sent for host commands is following this format:

    I would also check if the data write follows this format:

     

    The SPI mode should be mode 0 and MSB first.

    0

Please sign in to leave a comment.