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.

MSP430FR5994: The same code running more than 10x slower on MSP430FR5994 than on MSP430F5529

Part Number: MSP430FR5994
Other Parts Discussed in Thread: MSP430F5529,

Hi everyone,

here I have an issue with the same code running way slower on MSP430FR5994 than on MSP430F5529.

The code is for Pervasive EPD display and it is provided from Pervasive for MSP430F5529.

The only difference in the code is the code for SPI modules. MPS430FR5994 uses EUSCI and MSP430F5529 uses USCI modul for SPI communication. Proper adjustments have been made. Speed of transmition for both modules is the same 13.5 MHz (measured on osciloscope).

The working frequencies are pretty much the same. MSP430FR5994 = 24 MHz, MSP430F5529 = 25 MHz.

FRAM waiting cycles are set for MSP430FR5994.

Function stage_handle_Base(uint8_t *image_prt,long image_data_address, uint8_t stage_no,uint8_t lineoffset), take way more time when executing on MSP430FR5994. Maybe even more than 10x slower than on MSP430F5529. As I figured out the problem is in the inner loop whenever there are some memory accesses.

In main, among the other things that have to be done for setting the display up, function void display_from_array_prt (uint8_t *previous_image_ptr, uint8_t *new_image_ptr) is called.

I couldn't find a reason why this is like it is, maybe it is because FRAM is operating on 8 MHz and read cycles are way slower than on FLASH or SRAM.

I would really appreciate all the help I could get to speed this execution up on MSP430FR5994.

Thank you.

#define ADDRESS_NULL        0xffffffff
//EPD Panel parameters
const struct COG_parameters_t COG_parameters[COUNT_OF_EPD_TYPE]  = {
    {
        // FOR 1.44"
        {0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00},
        0x03,
        (128/8),
        96,
        ((((128+96)*2)/8)+1),
        0,
        480
    },
    {
        // For 2.0"
        {0x00,0x00,0x00,0x00,0x01,0xFF,0xE0,0x00},
        0x03,
        (200/8),
        96,
        ((((200+96)*2)/8)+1),
        0,
        480
    },
    {
        // For 2.7"
        {0x00,0x00,0x00,0x7F,0xFF,0xFE,0x00,0x00},
        0x00,
        (264/8),
        176,
        ((((264+176)*2)/8)+1),
        0,
        630
    }
};
/* \brief EPD Waveform parameters for Aurora Ma at Room Temperature
 * \note the parameters of waveform table below is different from the G2 COG document due to
 *       use block size is easier to achieve than accurate block time for different MCU.
 *       The approach is also working. */
const EPD_Aurora_Ma_RoomTemp_WaveformTable_Struct E_Room_Waveform[COUNT_OF_EPD_TYPE][3]  = {
    {// FOR 1.44"
        {//50>= T ¡Ö 40
            4,              //stage1_frame1
            16,             //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            4,              //stage3_frame3
            16,             //stage3_block3
            2               //stage3_step3
        }
        ,{//40>= T ¡Ö 10
            4,              //stage1_frame1
            16,             //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            4,              //stage3_frame3
            16,             //stage3_block3
            2               //stage3_step3
        }
        ,{//10>= T ¡Ö 0
            4,              //stage1_frame1
            16,             //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            4,              //stage3_frame3
            16,             //stage3_block3
            2               //stage3_step3
        }
    },
    {// For 2.0"
        {//50>= T ¡Ö 40
            4,              //stage1_frame1
            48,             //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            4,              //stage3_frame3
            48,             //stage3_block3
            2               //stage3_step3
        },
        {//40>= T ¡Ö 10
            2,              //stage1_frame1
            32,             //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            2,              //stage3_frame3
            32,             //stage3_block3
            2               //stage3_step3
        },
        {//10>= T ¡Ö 0
            3,              //stage1_frame1
            48,             //stage1_block1
            2,              //stage1_step1
            310,            //stage2_t1
            310,            //stage2_t2
            4,              //stage2_cycle
            3,              //stage3_frame3
            48,             //stage3_block3
            2               //stage3_step3
        }
    },
    {// For 2.7"
        {//50>= T ¡Ö 40
            4,              //stage1_frame1
            4,              //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            4,              //stage3_frame3
            22,             //stage3_block3
            2               //stage3_step3
        }
        ,{//40>= T ¡Ö 10
            2,              //stage1_frame1
            48,             //stage1_block1
            2,              //stage1_step1
            155,            //stage2_t1
            155,            //stage2_t2
            4,              //stage2_cycle
            2,              //stage3_frame3
            48,             //stage3_block3
            2               //stage3_step3
        }
        ,{//10>= T ¡Ö 0
            3,              //stage1_frame1
            16,             //stage1_block1
            2,              //stage1_step1
            310,            //stage2_t1
            310,            //stage2_t2
            4,              //stage2_cycle
            3,              //stage3_frame3
            16,             //stage3_block3
            2               //stage3_step3
        }
    }
};

/**
 * \brief Parameters for Aurora Ma at Low Temperature (sub zero degree C)
 * \note The parameters below are not yet determined. Please contact Pervasive Displays for furthur information.
 */
const EPD_Aurora_Ma_LowTemp_WaveformTable_Struct EPD_low_WaveformTable[COUNT_OF_EPD_TYPE][5]  = {
    {// FOR 2.0"
        {//0>= T ¡Ö -5
            560,            //stage1_FrameTime
            5,              //stage1_Cycle
            560,            //stage2_FrameTime
            840,            //stage3_FrameTime
            8,              //stage3_Cycle
            560             //stage4_FrameTime
        },
        {//-5>= T ¡Ö -10
            560,            //stage1_FrameTime
            10,             //stage1_Cycle
            560,            //stage2_FrameTime
            840,            //stage3_FrameTime
            10,             //stage3_Cycle
            560             //stage4_FrameTim
        },
        {//-10>= T ¡Ö -15
            560,            //stage1_FrameTime
            15,             //stage1_Cycle
            1400,           //stage2_FrameTime
            1120,           //stage3_FrameTime
            8,              //stage3_Cycle
            1400            //stage4_FrameTim
        },
        {//-15>= T ¡Ö -20
            560,            //stage1_FrameTime
            20,             //stage1_Cycle
            1960,           //stage2_FrameTime
            1120,           //stage3_FrameTime
            8,              //stage3_Cycle
            1960            //stage4_FrameTim
        },
        {//-20>= T
            560,            //stage1_FrameTime
            25,             //stage1_Cycle
            1960,           //stage2_FrameTime
            1120,           //stage3_FrameTime
            8,              //stage3_Cycle
            1960            //stage4_FrameTim
        }
    },
    {// FOR 2.7"
        {//0>= T ¡Ö -5
            760,            //stage1_FrameTime
            5,              //stage1_Cycle
            760,            //stage2_FrameTime
            1520,           //stage3_FrameTime
            8,              //stage3_Cycle
            760             //stage4_FrameTime
        },
        {//-5>= T ¡Ö -10
            760,            //stage1_FrameTime
            10,             //stage1_Cycle
            760,            //stage2_FrameTime
            1520,           //stage3_FrameTime
            10,             //stage3_Cycle
            760             //stage4_FrameTime
        },
        {//-10>= T ¡Ö -15
            760,            //stage1_FrameTime
            15,             //stage1_Cycle
            1140,           //stage2_FrameTime
            1520,           //stage3_FrameTime
            12,             //stage3_Cycle
            1140            //stage4_FrameTime
        },
        {//-15>= T ¡Ö -20
            760,            //stage1_FrameTime
            20,             //stage1_Cycle
            1520,           //stage2_FrameTime
            1520,           //stage3_FrameTime
            8,              //stage3_Cycle
            1520            //stage4_FrameTime
        },
        {//-20>= T
            760,            //stage1_FrameTime
            25,             //stage1_Cycle
            1520,           //stage2_FrameTime
            1520,           //stage3_FrameTime
            8,              //stage3_Cycle
            1520            //stage4_FrameTime
        }
    }
};

const uint8_t   SCAN_TABLE[4] = {0xC0,0x30,0x0C,0x03};

static EPD_Aurora_Ma_RoomTemp_WaveformTable_Struct *action__Waveform_param;
static COG_line_data_packet_type COG_Line;
static EPD_read_memory_handler _On_EPD_read_flash;
static uint8_t  *data_line_even;
static uint8_t  *data_line_odd;
static uint8_t  *data_line_scan;
static uint8_t  *data_line_border_byte;
static uint8_t cur_EPD_type_index=1;

/**
 * \brief According to EPD size and temperature to get stage_time
 * \note Refer to COG document Section 5.3 for more details
 *
 * \param EPD_type_index The defined EPD size
 */
static void set_temperature_factor(int8_t temperature) {
       action__Waveform_param=(EPD_Aurora_Ma_RoomTemp_WaveformTable_Struct *)&E_Room_Waveform[cur_EPD_type_index][1]; //Default
}

/**
 * \brief Select the EPD size to get line data array for driving COG
 *
 * \param EPD_type_index The defined EPD size
 */
void COG_driver_EPDtype_select(void) {
    switch(cur_EPD_type_index) {
        case EPD_144:
        data_line_even = &COG_Line.line_data_by_size.line_data_for_144.even[0];
        data_line_odd  = &COG_Line.line_data_by_size.line_data_for_144.odd[0];
        data_line_scan = &COG_Line.line_data_by_size.line_data_for_144.scan[0];
        data_line_border_byte = &COG_Line.line_data_by_size.line_data_for_144.border_byte;
        break;
        case EPD_200:
        data_line_even = &COG_Line.line_data_by_size.line_data_for_200.even[0];
        data_line_odd  = &COG_Line.line_data_by_size.line_data_for_200.odd[0];
        data_line_scan = &COG_Line.line_data_by_size.line_data_for_200.scan[0];
        data_line_border_byte = &COG_Line.line_data_by_size.line_data_for_200.border_byte;
        break;
        case EPD_270:
        data_line_even = &COG_Line.line_data_by_size.line_data_for_270.even[0];
        data_line_odd  = &COG_Line.line_data_by_size.line_data_for_270.odd[0];
        data_line_scan = &COG_Line.line_data_by_size.line_data_for_270.scan[0];
        data_line_border_byte = &COG_Line.line_data_by_size.line_data_for_270.border_byte;
        break;
    }
}

/**
 * \brief Power on COG Driver
 * \note For detailed flow and description, please refer to the COG G2 document Section 3.
 */

/*
void EPD_power_on (uint8_t EPD_type_index,int8_t temperature) {
    cur_EPD_type_index=EPD_type_index;

    EPD_Vcc_turn_on(); //Vcc and Vdd >= 2.7V
    EPD_cs_high();
    epd_spi_attach();
    EPD_border_high();
    EPD_rst_high();
    delay_ms(5);
    EPD_rst_low();
    delay_ms(5);
    EPD_rst_high();
    delay_ms(5);
    // Sense temperature to determine Temperature Factor
    set_temperature_factor(temperature);
}
*/

/**
 * \brief Initialize COG Driver
 * \note For detailed flow and description, please refer to the COG G2 document Section 4.
 */
uint8_t initialize_driver (void) {

    set_temperature_factor(25);
    uint16_t i;
    // Empty the Line buffer
    for (i = 0; i <= LINE_BUFFER_DATA_SIZE; i ++) {
        COG_Line.uint8[i] = 0x00;
    }
    // Determine the EPD size for driving COG
    COG_driver_EPDtype_select();

    i = 0;

    while (GPIO_getInputPinValue(EPD_BUSY_PORT, EPD_BUSY_PIN) == 1) {
        if((i++) >= 0x0FFF) return ERROR_BUSY;
    }

    //Check COG ID
    if((spi_R(0x72,0x00) & 0x0f) !=0x02) return ERROR_COG_ID;

    //Disable OE
    spi_send_byte(0x02,0x40);

    //Check Breakage
    if((spi_R(0x0F,0x00) & 0x80) != 0x80) return ERROR_BREAKAGE;

    //Power Saving Mode
    spi_send_byte(0x0B, 0x02);

    //Channel Select
    epd_spi_send (0x01, (uint8_t *)&COG_parameters[cur_EPD_type_index].channel_select, 8);

    //High Power Mode Osc Setting
    spi_send_byte(0x07,0xD1);

    //Power Setting
    spi_send_byte(0x08,0x02);

    //Set Vcom level
    spi_send_byte(0x09,0xC2);

    //Power Setting
    spi_send_byte(0x04,0x03);

    //Driver latch on
    spi_send_byte(0x03,0x01);

    //Driver latch off
    spi_send_byte(0x03,0x00);

    delay_ms(5);

    //Chargepump Start
    i=0;
    do {
        //Start chargepump positive V
        //VGH & VDH on
        spi_send_byte(0x05,0x01);

        delay_ms(240);

        //Start chargepump neg voltage
        //VGL & VDL on
        spi_send_byte(0x05,0x03);

        delay_ms(40);

        //Set chargepump
        //Vcom_Driver to ON
        //Vcom_Driver on
        spi_send_byte(0x05,0x0F);

        delay_ms(40);

        //Check DC/DC
        if((spi_R(0x0F,0x00) & 0x40) == 0x40)
        {
            //Output enable to disable
            spi_send_byte(0x02,0x04);
            break;
        }

    }while((i++) != 4);

    if(i>=4) return ERROR_CHARGEPUMP;
    else return RES_OK;
}


/**
 * \brief Initialize the parameters of Block type stage
 *
 * \param S_epd_AuroraMa The Block type waveform structure for Aurora_Ma
 * \param block_size The width of Block size
 * \param step_size The width of Step size
 * \param frame_cycle The width of Step size
 */
void stage_init(struct EPD_Aurora_Ma_Struct *S_epd_AuroraMa,
                uint8_t block_size,uint8_t step_size,
                uint8_t frame_cycle)
{
    S_epd_AuroraMa->frame_y0 = 0;
    S_epd_AuroraMa->frame_y1 = 176;
    S_epd_AuroraMa->block_y0 = 0;
    S_epd_AuroraMa->block_y1 = 0;
    S_epd_AuroraMa->step_y0 = 0;
    S_epd_AuroraMa->step_y1 = 0;
    S_epd_AuroraMa->block_size = action__Waveform_param->stage1_block1;
    S_epd_AuroraMa->step_size =action__Waveform_param->stage1_step1;
    S_epd_AuroraMa->frame_cycle = action__Waveform_param->stage1_frame1;
    S_epd_AuroraMa->number_of_steps = (COG_parameters[cur_EPD_type_index].vertical_size / S_epd_AuroraMa->step_size) + (action__Waveform_param->stage1_block1 / action__Waveform_param->stage1_step1) -1;

}

/**
 * \brief For Frame type waveform to update all black/white pattern
 *
 * \param bwdata Black or White color to whole screen
 * \param work_time The working time
 */
static inline void same_data_frame ( uint8_t bwdata, uint32_t work_time) {
    uint16_t i;
    for (i = 0; i <  COG_parameters[cur_EPD_type_index].horizontal_size; i++) {
        data_line_even[i]=bwdata;
        data_line_odd[i]=bwdata;
    }
    start_EPD_timer();
    do
    {
        for (i = 0; i < COG_parameters[cur_EPD_type_index].vertical_size; i++) {

            /* Scan byte shift per data line */
            data_line_scan[(i>>2)]=SCAN_TABLE[(i%4)];

            /* Sending data */
            epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8, COG_parameters[cur_EPD_type_index].data_line_size);

            /* Turn on Output Enable */
            spi_send_byte (0x02, 0x07);

            data_line_scan[(i>>2)]=0;

        }
    } while (get_counter()<(work_time));
        /* Stop system timer */
        stop_EPD_timer();
}

/**
 * \brief Write nothing Line to COG
 * \note A line whose all Scan Bytes are 0x00
 */
void nothing_line(void) {
    uint16_t i;
    for (i = 0; i <  COG_parameters[cur_EPD_type_index].horizontal_size; i++) {
        data_line_even[i]   =   NOTHING;
        data_line_odd[i]    =   NOTHING;
    }
}


/**
 * \brief Get line data of Stage 1 and 3
 *
 * \note
 * - One dot/pixel is comprised of 2 bits which are White(10), Black(11) or Nothing(01).
 *   The image data bytes must be divided into Odd and Even bytes.
 * - The COG driver uses a buffer to write one line of data (FIFO) - interlaced
 *   It's different order from COG_G1
 *   Odd byte {D(199,y),D(197,y), D(195,y), D(193,y)}, ... ,{D(7,y),D(5,y),D(3,y), D(1,y)}
 *   Scan byte {S(96), S(95)...}
 *   Odd byte  {D(2,y),D(4,y), D(6,y), D(8,y)}, ... ,{D(194,y),D(196,y),D(198,y), D(200,y)}
 * - For more details on the driving stages, please refer to the COG G2 document Section 5.
 *
 * \param image_ptr The pointer of memory that stores image that will send to COG
 * \param stage_no The assigned stage number that will proceed
 */

void read_line_data_handle(uint8_t *image_prt,uint8_t stage_no)
{
    int16_t x,k;
    uint8_t temp_byte; // Temporary storage for image data check
    k=COG_parameters[cur_EPD_type_index].horizontal_size-1;
    for (x =0 ; x < COG_parameters[cur_EPD_type_index].horizontal_size ; x++) {
                temp_byte = *image_prt++;
                switch(stage_no) {
                    case Stage1: // Inverse image
                    /* Example at stage 1 to get Even and Odd data. It's different order from G1.
                    * +---------+----+----+----+----+----+----+----+----+
                    * |         |bit7|bit6|bit5|bit4|bit3|bit2|bit1|bit0|
                    * |temp_byte+----+----+----+----+----+----+----+----+
                    * |         |  1 |  0 |  1 |  1 |  0 |  1 |  0 |  0 |
                    * +---------+----+----+----+----+----+----+----+----+ */
                    data_line_odd[x]       = ((temp_byte & 0x40) ? BLACK3  : WHITE3); // WHITE3 = 0x80 = 1000 0000
                    data_line_odd[x]      |= ((temp_byte & 0x10) ? BLACK2  : WHITE2); // BLACK2 = 0x30 = 0011 0000
                    data_line_odd[x]      |= ((temp_byte & 0x04) ? BLACK1  : WHITE1); // BLACK1 = 0x0C = 0000 1100
                    data_line_odd[x]      |= ((temp_byte & 0x01) ? BLACK0  : WHITE0); // WHITE0 = 0x02 = 0000 0010
                    /* data_line_odd[x] = 1000 0000 | 0011 0000 | 0000 1100 | 0000 0010 = 1011 1110 ==> 1011 1110
                    * See Even data row at the table below*/

                    data_line_even[k]    = ((temp_byte & 0x80) ? BLACK0  : WHITE0); // BLACK0 = 0x03 = 0000 0011
                    data_line_even[k]   |= ((temp_byte & 0x20) ? BLACK1  : WHITE1); // BLACK1 = 0x0C = 0000 1100
                    data_line_even[k]   |= ((temp_byte & 0x08) ? BLACK2  : WHITE2); // WHITE2 = 0x20 = 0010 0000
                    data_line_even[k--] |= ((temp_byte & 0x02) ? BLACK3  : WHITE3); // WHITE3 = 0x80 = 1000 0000
                    /* data_line_even[k] = 0000 0011 | 0000 1100 | 0010 0000 | 1000 0000 = 1010 1111 ==> 1111 1010
                    * See Odd data row at the table below
                    * +---------+----+----+----+----+----+----+----+----+
                    * |         |bit7|bit6|bit5|bit4|bit3|bit2|bit1|bit0|
                    * |temp_byte+----+----+----+----+----+----+----+----+
                    * |         |  1 |  0 |  1 |  1 |  0 |  1 |  0 |  0 |
                    * +---------+----+----+----+----+----+----+----+----+
                    * | Color   |  W |  B |  W |  W |  B |  W |  B |  B | W=White, B=Black, N=Nothing
                    * +---------+----+----+----+----+----+----+----+----+
                    * | Stage 1 |  B |  W |  B |  B |  W |  B |  W |  W | Inverse
                    * +---------+----+----+----+----+----+----+----+----+
                    * | Input   | 11 | 10 | 11 | 11 | 10 | 11 | 10 | 10 | W=10, B=11, N=01
                    * +---------+----+----+----+----+----+----+----+----+
                    * |Even data| 11 |    | 11 |    | 10 |    | 10 |    | = 1111 1010
                    * +---------+----+----+----+----+----+----+----+----+
                    * |Odd data |    | 10 |    | 11 |    | 11 |    | 10 | = 1011 1110
                    * +---------+----+----+----+----+----+----+----+----+ */
                    break;
                    case Stage3: // New image
                        data_line_odd[x]         = ((temp_byte & 0x40) ? WHITE3  : BLACK3 );
                        data_line_odd[x]        |= ((temp_byte & 0x10) ? WHITE2  : BLACK2 );
                        data_line_odd[x]        |= ((temp_byte & 0x04) ? WHITE1  : BLACK1 );
                        data_line_odd[x]        |= ((temp_byte & 0x01) ? WHITE0  : BLACK0 );

                        data_line_even[k]        = ((temp_byte & 0x80) ? WHITE0  : BLACK0 );
                        data_line_even[k]       |= ((temp_byte & 0x20) ? WHITE1  : BLACK1 );
                        data_line_even[k]       |= ((temp_byte & 0x08) ? WHITE2  : BLACK2 );
                        data_line_even[k--]     |= ((temp_byte & 0x02) ? WHITE3  : BLACK3 );
                    break;
                }
        }
}


/**
 * \brief The base function to handle the driving stages for Frame and Block type
 *
 * \note
 * - There are 3 stages to complete an image update cycle on AuroraMa_G2 type EPD.
 * - For more details on the driving stages, please refer to the COG G2 document Section 5.4
 *
 * \param image_ptr The pointer of image array that stores image that will send to COG
 * \param image_data_address The address of memory that stores image
 * \param stage_no The assigned stage number that will proceed
 * \param lineoffset Line data offset
 */
void stage_handle_Base(uint8_t *image_prt,long image_data_address,
                        uint8_t stage_no,uint8_t lineoffset)
{
    struct EPD_Aurora_Ma_Struct S_epd_AuroraMa;
    int16_t cycle,m,i; //m=number of steps
    //uint8_t isLastframe = 0;  //If it is the last frame to send Nothing at the fist scan line
    uint8_t isLastBlock=0;      //If the beginning line of block is in active range of EPD
    int16_t scanline_no=0;
    uint8_t *action_block_prt;
    long action_block_address;
    uint8_t byte_array[LINE_BUFFER_DATA_SIZE];
    /** Stage 2: BLACK/WHITE image, Frame type */
    if(stage_no==Stage2)
    {
        for(i=0;i<action__Waveform_param->stage2_cycle;i++)
        {
            same_data_frame (ALL_BLACK,action__Waveform_param->stage2_t1);
            same_data_frame (ALL_WHITE,action__Waveform_param->stage2_t2);
        }
        return;
    }
    /** Stage 1 & 3, Block type */
    // The frame/block/step of Stage1 and Stage3 are default the same.
    stage_init( &S_epd_AuroraMa,
                action__Waveform_param->stage1_block1,
                action__Waveform_param->stage1_step1,
                action__Waveform_param->stage1_frame1);

     /* Repeat number of frames */
     for (cycle = 0; cycle < (S_epd_AuroraMa.frame_cycle ); cycle++)
     {

        // if (cycle == (S_epd_AuroraMa.frame_cycle - 1)) isLastframe = 1;

         isLastBlock = 0;
         S_epd_AuroraMa.step_y0 = 0;
         S_epd_AuroraMa.step_y1 = S_epd_AuroraMa.step_size ;
         S_epd_AuroraMa.block_y0 = 0;
         S_epd_AuroraMa.block_y1 = 0;
         /* Move number of steps */
         for (m = 0; m < S_epd_AuroraMa.number_of_steps; m++)
         {
             S_epd_AuroraMa.block_y1 += S_epd_AuroraMa.step_size;
             S_epd_AuroraMa.block_y0 = S_epd_AuroraMa.block_y1 - S_epd_AuroraMa.block_size;
            /* reset block_y0=frame_y0 if block is not in active range of EPD */
             if (S_epd_AuroraMa.block_y0 < S_epd_AuroraMa.frame_y0) S_epd_AuroraMa.block_y0 = S_epd_AuroraMa.frame_y0;

            /* if the beginning line of block is in active range of EPD */
             if (S_epd_AuroraMa.block_y1 == S_epd_AuroraMa.block_size) isLastBlock = 1;

             if(image_prt!=NULL)
             {
                 action_block_prt=(image_prt+(int)(S_epd_AuroraMa.block_y0*lineoffset));
             }
             else if(_On_EPD_read_flash!=NULL)  //Read line data in range of block, read first
             {
                action_block_address=image_data_address+(long)(S_epd_AuroraMa.block_y0*lineoffset);
                _On_EPD_read_flash(action_block_address,(uint8_t *)&byte_array,
                                    COG_parameters[cur_EPD_type_index].horizontal_size);
                action_block_prt=(uint8_t *)&byte_array;
             }
            /* Update line data */
             for (i = S_epd_AuroraMa.block_y0; i < S_epd_AuroraMa.block_y1; i++)
             {

                 if (i >= COG_parameters[cur_EPD_type_index].vertical_size) break;
                 //if (isLastframe &&
                 if (
                  isLastBlock &&(i < (S_epd_AuroraMa.step_size + S_epd_AuroraMa.block_y0)))
                  {
                      nothing_line();
                  }
                  else
                  {
                      read_line_data_handle(action_block_prt,stage_no);
                  }

                if(_On_EPD_read_flash!=NULL)    //Read line data in range of block
                {
                    action_block_address +=lineoffset;
                    _On_EPD_read_flash(action_block_address,(uint8_t *)&byte_array,
                    COG_parameters[cur_EPD_type_index].horizontal_size);
                    action_block_prt=(uint8_t *)&byte_array;
                }
                else action_block_prt+=lineoffset;

                scanline_no= (COG_parameters[cur_EPD_type_index].vertical_size-1)-i;

                /* Scan byte shift per data line */
                data_line_scan[(scanline_no>>2)] = SCAN_TABLE[(scanline_no%4)];

                /*  the border uses the internal signal control byte. */
                *data_line_border_byte=0x00;

                /* Sending data */
                epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8,
                COG_parameters[cur_EPD_type_index].data_line_size);


                /* Turn on Output Enable */
                spi_send_byte (0x02, 0x07);

                data_line_scan[(scanline_no>>2)]=0;

             }
         }

    }
}

/**
 * \brief The driving stages from image array (image_data.h) to COG
 *
 * \param image_ptr The pointer of image array that stores image that will send to COG
 * \param stage_no The assigned stage number that will proceed
 * \param lineoffset Line data offset
 */
void stage_handle(uint8_t *image_prt,uint8_t stage_no,uint8_t lineoffset)
{
    stage_handle_Base(image_prt,ADDRESS_NULL,stage_no,lineoffset);
}

/**
 * \brief The driving stages from memory to COG
 *
 * \note
 * - This function is additional added here for developer if the image data
 *   is stored in Flash memory.
 *
 * \param image_data_address The address of flash memory that stores image
 * \param stage_no The assigned stage number that will proceed
 * \param lineoffset Line data offset
 */
static void stage_handle_ex(long image_data_address,uint8_t stage_no,uint8_t lineoffset) {
    stage_handle_Base(NULL,image_data_address,stage_no,lineoffset);
}

/**
 * \brief Write image data from memory array (image_data.h) to the EPD
 *
 * \param previous_image_ptr The pointer of memory that stores previous image
 * \param new_image_ptr The pointer of memory that stores new image
 */
void display_from_array_prt (uint8_t *previous_image_ptr,
        uint8_t *new_image_ptr) {
    _On_EPD_read_flash=0;
    stage_handle(new_image_ptr,Stage1,COG_parameters[cur_EPD_type_index].horizontal_size);
    stage_handle(new_image_ptr,Stage2,COG_parameters[cur_EPD_type_index].horizontal_size);
    stage_handle(new_image_ptr,Stage3,COG_parameters[cur_EPD_type_index].horizontal_size);
}

/**
 * \brief Write image data from Flash memory to the EPD
 * \note This function is additional added here for developer if the image data
 * is stored in Flash.
 *
 * \param previous_image_flash_address The start address of memory that stores previous image
 * \param new_image_flash_address The start address of memory that stores new image
 * \param On_EPD_read_flash Developer needs to create an external function to read flash
 */
void display_from_flash_prt (long previous_image_flash_address,
    long new_image_flash_address,EPD_read_memory_handler On_EPD_read_flash) {

    uint8_t line_len;
    line_len=Line_Offset(cur_EPD_type_index);
    if(line_len==0) line_len=COG_parameters[cur_EPD_type_index].horizontal_size;

    _On_EPD_read_flash=On_EPD_read_flash;
    stage_handle_ex(new_image_flash_address,Stage1,line_len);
    stage_handle_ex(new_image_flash_address,Stage2,line_len);
    stage_handle_ex(new_image_flash_address,Stage3,line_len);
}


/**
 * \brief Write Dummy Line to COG
 * \note A line that all Data and Scan Bytes are 0x00
 */
void dummy_line(void) {
    uint8_t i;
    for (i = 0; i < (COG_parameters[cur_EPD_type_index].vertical_size/8); i++) {
        COG_Line.uint8[i] = 0x00;
    }

    /* Sending data */
    epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8, COG_parameters[cur_EPD_type_index].data_line_size);

    /* Turn on Output Enable */
    spi_send_byte (0x02, 0x07);
}



/**
* \brief Write Border(Input) Dummy Line
*/
static void border_dummy_line(void)
{
    uint16_t    i;
    for (i =0 ; i < COG_parameters[cur_EPD_type_index].horizontal_size ; i++)
    {
        data_line_odd[i]=0x55;
        data_line_even[i]=0x55;
    }

    for (i = 0; i < (COG_parameters[cur_EPD_type_index].vertical_size/8); i++)
    {
        data_line_scan[i] =0x00;
    }

    *data_line_border_byte=BORDER_BYTE_W;
    //Write a Borde(B) Dummy Line
    epd_spi_send (0x0a, (uint8_t *)&COG_Line.uint8, COG_parameters[cur_EPD_type_index].data_line_size);
    //Turn on OE
    spi_send_byte (0x02, 0x07);

}

/**
 * \brief Write Nothing Frame to COG
 * \note A frame that all D(x,y) are N(01). 0101=0x55=NOTHING
 */
void nothing_frame (void) {
    uint16_t i;
    for (i = 0; i <  COG_parameters[cur_EPD_type_index].horizontal_size; i++) {
        data_line_even[i]=NOTHING;
        data_line_odd[i]=NOTHING;
    }

    for (i = 0; i < COG_parameters[cur_EPD_type_index].vertical_size; i++) {

        /* Scan byte shift per data line */
        data_line_scan[(i>>2)]=SCAN_TABLE[(i%4)];

        /* Sending data */
        epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8, COG_parameters[cur_EPD_type_index].data_line_size);

        /* Turn on Output Enable */
        spi_send_byte (0x02, 0x07);

        data_line_scan[(i>>2)]=0;
    }
}
/**
* \brief Power Off COG Driver
* \note For detailed flow and description, please refer to the COG G2 document Section 6.
*/
uint8_t power_off(void) {

    nothing_frame();
    if(cur_EPD_type_index==EPD_144 || cur_EPD_type_index==EPD_200)
    {
        border_dummy_line();
        delay_ms (200);
    }


    if(cur_EPD_type_index==EPD_270) {
        dummy_line();
        delay_ms (25);
        EPD_BORDER_low();
        delay_ms (200);
        EPD_BORDER_high();
    }

    spi_send_byte (0x0B, 0x00);

    //Turn on Latch Reset
    spi_send_byte (0x03, 0x01);
    //Power off charge pump Vcom
    spi_send_byte (0x05, 0x03);
    //Power off charge pump neg voltage
    spi_send_byte (0x05, 0x01);
    delay_ms(120);
    spi_send_byte (0x04, 0x80);
    //Turn off all charge pump
    spi_send_byte (0x05, 0x00);

    //Turn off OSC
    spi_send_byte (0x07, 0x01);
    delay_ms(50);

   spi_detach ();
    EPD_BORDER_low()
    //EPD_border_low();
    EPD_PANELON_low()
    //EPD_Vcc_turn_off ();
    delay_ms (10);

    cs_low();
    //EPD_cs_low();
    EPD_RESET_low()
   // EPD_rst_low();

    EPD_DISCHARGE_high()
    //EPD_discharge_high ();
    delay_ms (150);
    EPD_DISCHARGE_low()
    //EPD_discharge_low ();


    return RES_OK;
}

  • Hi, 

    You've posted a very large portion of code that is far too much for me to debug. Please reduce your code to a smaller set that still exhibits the issue so it is easier to review.

    Sladjan Dragicevic said:
    The working frequencies are pretty much the same. MSP430FR5994 = 24 MHz, MSP430F5529 = 25 MHz.

    The MSP430FR5994 has a maximum frequency of 16MHz. Anything above this is out of spec and I can't guarantee reliable operation.

    Best regards, 
    Caleb Overbay

  • Caleb,

    sorry for portion of the code. I've reduced it to a function where the stall is.

    Yes, by the specs operating freq of FR5994 is 16MHz. I've overclocked it to 24 to run faster. And it runs the code a bit faster than on 16 MHz. But even on 24 MHz it is more than 10 times slower than the same code running on MSP430F5529 at 25MHz.

    The function where the stall is provided bellow. Functions called in this portion of code are provided in original post.

    void stage_handle_Base(uint8_t *image_prt,long image_data_address,
                            uint8_t stage_no,uint8_t lineoffset)
    {
        struct EPD_Aurora_Ma_Struct S_epd_AuroraMa;
        int16_t cycle,m,i; //m=number of steps
        //uint8_t isLastframe = 0;  //If it is the last frame to send Nothing at the fist scan line
        uint8_t isLastBlock=0;      //If the beginning line of block is in active range of EPD
        int16_t scanline_no=0;
        uint8_t *action_block_prt;
        long action_block_address;
        uint8_t byte_array[LINE_BUFFER_DATA_SIZE];
        /** Stage 2: BLACK/WHITE image, Frame type */
        if(stage_no==Stage2)
        {
            for(i=0;i<action__Waveform_param->stage2_cycle;i++)
            {
                same_data_frame (ALL_BLACK,action__Waveform_param->stage2_t1);
                same_data_frame (ALL_WHITE,action__Waveform_param->stage2_t2);
            }
            return;
        }
        /** Stage 1 & 3, Block type */
        // The frame/block/step of Stage1 and Stage3 are default the same.
        stage_init( &S_epd_AuroraMa,
                    action__Waveform_param->stage1_block1,
                    action__Waveform_param->stage1_step1,
                    action__Waveform_param->stage1_frame1);

         /* Repeat number of frames */
         for (cycle = 0; cycle < (S_epd_AuroraMa.frame_cycle ); cycle++)
         {

            // if (cycle == (S_epd_AuroraMa.frame_cycle - 1)) isLastframe = 1;

             isLastBlock = 0;
             S_epd_AuroraMa.step_y0 = 0;
             S_epd_AuroraMa.step_y1 = S_epd_AuroraMa.step_size ;
             S_epd_AuroraMa.block_y0 = 0;
             S_epd_AuroraMa.block_y1 = 0;
             /* Move number of steps */
             for (m = 0; m < S_epd_AuroraMa.number_of_steps; m++)
             {
                 S_epd_AuroraMa.block_y1 += S_epd_AuroraMa.step_size;
                 S_epd_AuroraMa.block_y0 = S_epd_AuroraMa.block_y1 - S_epd_AuroraMa.block_size;
                /* reset block_y0=frame_y0 if block is not in active range of EPD */
                 if (S_epd_AuroraMa.block_y0 < S_epd_AuroraMa.frame_y0) S_epd_AuroraMa.block_y0 = S_epd_AuroraMa.frame_y0;

                /* if the beginning line of block is in active range of EPD */
                 if (S_epd_AuroraMa.block_y1 == S_epd_AuroraMa.block_size) isLastBlock = 1;

                 if(image_prt!=NULL)
                 {
                     action_block_prt=(image_prt+(int)(S_epd_AuroraMa.block_y0*lineoffset));
                 }
                 else if(_On_EPD_read_flash!=NULL)  //Read line data in range of block, read first
                 {
                    action_block_address=image_data_address+(long)(S_epd_AuroraMa.block_y0*lineoffset);
                    _On_EPD_read_flash(action_block_address,(uint8_t *)&byte_array,
                                        COG_parameters[cur_EPD_type_index].horizontal_size);
                    action_block_prt=(uint8_t *)&byte_array;
                 }
                /* Update line data */
                 for (i = S_epd_AuroraMa.block_y0; i < S_epd_AuroraMa.block_y1; i++)
                 {

                     if (i >= COG_parameters[cur_EPD_type_index].vertical_size) break;
                     //if (isLastframe &&
                     if (
                      isLastBlock &&(i < (S_epd_AuroraMa.step_size + S_epd_AuroraMa.block_y0)))
                      {
                          nothing_line();
                      }
                      else
                      {
                          read_line_data_handle(action_block_prt,stage_no);
                      }

                    if(_On_EPD_read_flash!=NULL)    //Read line data in range of block
                    {
                        action_block_address +=lineoffset;
                        _On_EPD_read_flash(action_block_address,(uint8_t *)&byte_array,
                        COG_parameters[cur_EPD_type_index].horizontal_size);
                        action_block_prt=(uint8_t *)&byte_array;
                    }
                    else action_block_prt+=lineoffset;

                    scanline_no= (COG_parameters[cur_EPD_type_index].vertical_size-1)-i;

                    /* Scan byte shift per data line */
                    data_line_scan[(scanline_no>>2)] = SCAN_TABLE[(scanline_no%4)];

                    /*  the border uses the internal signal control byte. */
                    *data_line_border_byte=0x00;

                    /* Sending data */
                    epd_spi_send (0x0A, (uint8_t *)&COG_Line.uint8,
                    COG_parameters[cur_EPD_type_index].data_line_size);


                    /* Turn on Output Enable */
                    spi_send_byte (0x02, 0x07);

                    data_line_scan[(scanline_no>>2)]=0;

                 }
             }

        }
    }

  • Hi Sladjan,

    I don't advise that you overclock the part and I suspect that the increased frequency combined with wait states is what's causing the issue. When you're operating out of spec I can't guarantee proper operation and the part may act unexpectedly.

    Best regards,
    Caleb Overbay
  • I think code is optimize for MSP430F5529, which was written by Pervasive, that why it is running slow on MSP430FR5994 .
  • MSP430F5529 and MSP430FR5994 are with same CPUXV2, so I doubt that optimization is issue here.
  • Dear Caleb,

    thank you for your advice.

    Overclocking is not the issue here. When I set the clocks of both controllers to 16 MHz the code is still running 10 times faster on MPS430F5529 than on MSP430FR5994.

    The code by itself is not optimized for any of those. It is a C code and it should run at the same speed on both if the speed of main clocks are the same.

    Kind regards,

    Sladjan

  • Zrno Soli,

    the code by itself is not optimized for any of the controllers. Compilers of those can have influence but I doubt that.

    There can't be that the same code is running so much slower on one MCU than on another. Even that they are at the same speed of main clock.

    If I don't get any support from TI on this matter I have to abandon develpoment on MSP430FR5994.
    And probably abandon TI MCUs forever.

    This issue here is unacceptable!

    Best regards,
    Sladjan
  • Hi Sladjan,

    At 16MHz, wait states are still being used in the FR5994. I don't see any significant hardware differences other than this that could be causing the issue (e.g. hardware multipliers, etc). You mentioned that the portion of code where the problem occurs is accessing FRAM a lot. I think a good test would be to run both devices at 8MHz where wait states are not necessary on the FR5994 and compare the execution time. can you try this out and let me know the results?

    Best regards,
    Caleb Overbay
  • Hi Caleb,

    I did what you suggested. Both MCU set up for 8 MHz. Situation pretty much the same. FR5994 is way slower. Like 10 times.

    Regards,

    Sladjan

  • Hi Sladjan,

    This is a little perplexing. How are you measuring the time difference between the two sets of code?

    The code is fairly difficult to read, so I'm not sure what could be causing this issue. I did see that you were running the SPI at 13.5MHz which is relativity fast. Are you sure that you're not exceeding the maximum SPI communication speed on this device? You can find a description of how to perform the calculation in Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430 MCUs Section 4.2.

    Best regards, 
    Caleb Overbay

  • Caleb,

    First of all, sorry I've stated before that SPI CLK is 13.5 but instead it was 12 MHz.

    I've tested MSP4305994 at various SPI clock speed. (Slave supports up to around 13MHz)
    There is no big difference between SPICLK of 5MHz, 6MHz, 10MHz or 12MHz. (12MHz supported, transmission runs great)
    SPI transmission happens fast, and than there is a big delay till the next transmission. Every transmission is stated in the loop where the data for sending are updated.
    On MSP430F5529 there is no that delay. So, between transmissions, FR5994 is executing the same code 10x slower than F5529.


    All in all, SPI runs great, but MCU is too slow.(which by the specs. should be way faster!)

    To measure the time, I used a stopwatch. There is my human reaction time included, but difference between two MCUs is obvious.

    Looking forward for more support.
    Regards Sladjan
  • Hi Sladjan,

    I apologize for the delay in response. I've been reviewing your code and I still can't find a reason for the slow behavior you're experiencing. Have you been able to make any progress? I'm afraid there's not much more I can do without having the display to test the code on.

    Best regards,
    Caleb Overbay
  • Hi  Caleb,

    for the reply it's ok.

    I've tried various things to speed it up, but no success.

    Tried to run the code on similar MCUs of TI and other vendors at the same frequencies. MSP430FR5994 is simply way, way slower. Checked the architecuture with MSP430F5529. It's the same.

    After all, I couldn't find the problem or the speed up.

    Extension board is Pervasive EPD Extension Board Gen2 (EXT2) - 02. The display used is ETC G2 Aurora Ma (2 inch).

    Best regards,

    Sladjan

**Attention** This is a public forum