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.

CCS/TMS320F28035: How to access an EEPROM via SPI

Part Number: TMS320F28035

Tool/software: Code Composer Studio

CCS: V8

I want to access an EEPROM(Microchip/25AA320A) via DSP SPI. I coded my program(attached in the end),

My program give me an waveform (below) for writting data to EEPROM. CS will be set to low before sending each data, and set to high after sending each data.

But, I hope "CS set to low before sending data, and set to high after sending ALL data. Just like my EEPROM required (see waveform 2)

The data include an 8-bit write command, an 16-bit address and an 8-bit data written to EEPROM

Any suggestion?

waveform1

waveform2

Below is my program

SPI code

SI_GUI_Spi.c
#include "SI_GUI_Spi.h"

#include "DSP2803x_Device.h"     // DSP28 Headerfile Include File
#include "DSP2803x_Examples.h"   // DSP28 Examples Include File
#include "common.h"

#define EEPROM_CS GpioDataRegs.GPADAT.bit.GPIO19

#define RDSR        0b00000101          // RDSR  command 
#define WREN        0b00000110          // WREN  command 
#define WRITE       0b00000010          // WRITE command
#define READ        0b00000011          // READ  command

void spi_init(void);
Uint16 spi_xmit(int a);

void setup_EEPROM_SPI(void) {
    InitSpiaGpio();
    spi_init();
}

void spi_init(void) {
    SpiaRegs.SPICCR.all         = 0x0007; 	//Data is ready on rising edge), loopback is off, 8-bit data
    SpiaRegs.SPICTL.all         = 0x000E;   //Normal SPI clocking scheme(Data in latch on rising edge)master, 4-pin option, No interrupt
    SpiaRegs.SPIBRR             = 0x0077;   //BateRate 0.5MHz
    SpiaRegs.SPICCR.all         = 0x0087;   //SPI is ready to transmit or receive the next character.
    SpiaRegs.SPIPRI.bit.FREE    = 1;

    //EEPROM_CS                   = 1;
}

void read_EEPROM_Status(void) {
    //EEPROM_CS = 0;
    DELAY_US(1);
    spi_xmit(RDSR);
    //EEPROM_CS = 1;
    DELAY_US(100);
}

Uint16 spi_xmit(int a) {
    Uint16 Ret_var = 0;

    SpiaRegs.SPITXBUF = (a<<8);
    while(SpiaRegs.SPISTS.bit.INT_FLAG == 0);
    Ret_var = SpiaRegs.SPIRXBUF<<8;

    return Ret_var;
}

void addrwrite_EEPROM(Uint16 address,Uint16 Data) {
    int addrH,addrL;
    addrH = 0;
    addrL = 0;
    addrH = (address>>8);
    addrL = (address&0x00FF);

//write sequence..
//    EEPROM_CS = 0;
    DELAY_US(1);
    spi_xmit(WREN);
//    EEPROM_CS = 1;
    DELAY_US(1);

 //   EEPROM_CS = 0;
    DELAY_US(1);
    spi_xmit(WRITE);
    spi_xmit(addrH);
    spi_xmit(addrL);
    spi_xmit(Data);

    DELAY_US(1);
//    EEPROM_CS = 1;
    DELAY_US(10);
}

Uint16 addrread_EEPROM(Uint16 address) {
    Uint16 Ret_var=0;

    int addrH,addrL;

    addrH = 0;
    addrL = 0;
    addrH = (address>>8);
    addrL = (address&0x00FF);

  //  EEPROM_CS = 0;
    DELAY_US(1);
    spi_xmit(READ);
    spi_xmit(addrH);
    spi_xmit(addrL);
    Ret_var = spi_xmit(0);
    DELAY_US(1);
 //   EEPROM_CS = 1;
    DELAY_US(100);

    return Ret_var;
}

main

SI_GUI_Main.c
#include "DSP28x_Project.h"     // Device Headerfile and Examples Include File
#include "SI_GUI_Main.h"

void main(void) {
    Uint16  eeprom_data = 0x55;
    Uint16  eeprom_d1;
    Uint16  eeprom_addr = 0x03;
	setupDevice();		//will call setup_EEPROM_SPI
	read_EEPROM_Status();

	while (1){
	    addrwrite_EEPROM(eeprom_addr,eeprom_data);
	    eeprom_d1 = addrread_EEPROM(eeprom_addr);
 }
}

void Test() {
    char Message[9] = "W  Grid ";           //�dz��ഫ���ֺ�e�q�Ҧ�

    IBDC_PowerGeneration = 25 | 0x8000;     //MSB�]��1����F�o�q�q 25*0.1kW = 2.5kW
    INV_PowerGeneration  = 30 | 0x8000;     //MSB�]��1����F�o�q�q 30*0.1kW = 3.0kW
    PV_PowerGeneration   = 50;              //�S�����t���F�o�q�q 50*0.1kW = 5.0kW
    PVINV_ErrCode        = 123;             //���~�X�|�H10�i����ܡG123
    PVINV_WarningCode    = 567;             //ĵ�ܽX�|�H10�i����ܡG567
    IBDC_ErrCode         = 135;             //���~�X�|�H10�i����ܡG135
    IBDC_WarningCode     = 246;             //ĵ�ܽX�|�H10�i����ܡG246

    Display_Msg(Message);
}

void ErrCode(void){
    if (PVINV_ErrCode || IBDC_ErrCode) {//�p�G������o�X���~�X
        if (PVINV_ErrCode >= PVINV_ERROR_NUMBER-1)  PVINV_ErrCode = PVINV_ERROR_NUMBER-1;
        if (IBDC_ErrCode >= IBDC_ERROR_NUMBER-1)    IBDC_ErrCode  = IBDC_ERROR_NUMBER-1;
        LcmF=1;
        ErrCounter++;
    }
    else
        while(ErrCounter>=1 & PVINV_ErrCode==0 & IBDC_ErrCode==0){
            if(ErrCounter!=0)
                LCD_Display(PVINV_ErrorMsg[PVINV_ErrCode], IBDC_ErrorMsg[IBDC_ErrCode]);
            if (!bScanKeyTrigger) {KeyEvent = KeyEvent_Shadow; KeyEvent_Shadow = KEYEVENT_NO_EVENT;}
            if(KeyEvent==6){
                LcmF=0;
                ErrCounter=0;
                init_SI_GUI();
                return;
            }
            if (KeyEvent != KEYEVENT_NO_EVENT) {bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;}
        }
}

void System_Oper(void){
    if(LcmF==1){return;}
     //���s����ƥ�A�h��s����ƥ�
    if (!bScanKeyTrigger) {KeyEvent = KeyEvent_Shadow; KeyEvent_Shadow = KEYEVENT_NO_EVENT;}
    if (ModeSel_Action_F) {
        if (KeyEvent != KEYEVENT_NO_EVENT) {//����LMenu_ModeSel_Action()�S���F����F
            ModeSel_Action_F = 0; bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;
        } else return;
    }
    switch (nFuntionIndex) {//���ާ@�G���n�M������ƥ�A���U�|�B�z
    case _Menu_EntryPoint_Index:    Menu_EntryPoint();  break;
    case _Menu_ModeParaSel_Index:   Menu_ModeParaSel(); break;
    case _Menu_ModeSel_Index:       Menu_ModeSel();     break;
    case _Menu_ParaSet_Index:       Menu_ParaSet();     break;
    }
    //����ƥ�B�z�����A���s�Ұʫ��䱽�y�òM������ƥ�
    if (KeyEvent != KEYEVENT_NO_EVENT) {bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;}

}

void UpdataLCMs(void){
    if(LcmF==1)
        LCD_Display(PVINV_ErrorMsg[PVINV_ErrCode], IBDC_ErrorMsg[IBDC_ErrCode]);
    else if(LcmF==0){return;}

}

void Display_Msg(char *dispMsg) {
    char    LCD01[17], LCD02[17];
    Uint16  index, remain_Value;

    LCD01[16] = LCD02[16] = '\0';   //�]�w�r�굲���Ÿ�

    for (index=0; index < 8; index++) LCD01[index] = dispMsg[index];    //�ƻs�B��Ҧ�
    LCD01[8] = ((PV_PowerGeneration & 0x7FFF)/10)+'0';                  //�ഫPV�o�q�q
    LCD01[9] = ((PV_PowerGeneration & 0x7FFF)%10)+'0';

    if ((IBDC_PowerGeneration & 0x8000) > 0)    LCD01[10] = '+';        //�M�wIBDC�o�q�q�����t��
    else                                        LCD01[10] = '-';
    LCD01[11] = ((IBDC_PowerGeneration & 0x7FFF)/10)+'0';               //�ഫIBDC�o�q�q
    LCD01[12] = ((IBDC_PowerGeneration & 0x7FFF)%10)+'0';

    if ((INV_PowerGeneration & 0x8000) > 0)     LCD01[13] = '+';        //�M�wINV�o�q�q�����t��
    else                                        LCD01[13] = '-';
    LCD01[14] = ((INV_PowerGeneration & 0x7FFF)/10)+'0';                //�ഫINV�o�q�q
    LCD01[15] = ((INV_PowerGeneration & 0x7FFF)%10)+'0';

    remain_Value = PVINV_ErrCode;                                       //�ഫPVINV�����~�X
    LCD02[2]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[1]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[0]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    //LCD02[0]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[3]  = ' ';

    remain_Value = PVINV_WarningCode;                                   //�ഫPVINV��ĵ�ܽX
    LCD02[6]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[5]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[4]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    //LCD02[4]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[7]  = ' ';

    remain_Value = IBDC_ErrCode;                                        //�ഫIBDC�����~�X
    LCD02[10]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[9]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[8]   = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    //LCD02[8]   = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[11]  = ' ';

    remain_Value = IBDC_WarningCode;                                    //�ഫIBDC��ĵ�ܽX
    LCD02[14]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[13]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[12]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    //LCD02[12]  = remain_Value%10 + '0'; remain_Value = remain_Value/10;
    LCD02[15]  = ' ';
    LCD_Display(LCD01, LCD02);
}


void UpdateLEDs(void) {//��sLED
    int Led_Green_On = 1;

	//�����~�X�A�I�G���~���ܿO
	if (PVINV_ErrCode || IBDC_ErrCode)          {LED_RED_ON; Led_Green_On=0;}
	else								        {LED_RED_OFF;}

	if (PVINV_WarningCode || IBDC_WarningCode)  {LED_YELLOW_ON; Led_Green_On=0;}
	else										{LED_YELLOW_OFF;}

	if (Led_Green_On)                           LED_GREEN_ON;
	else                                        LED_GREEN_OFF;
}

void init_SI_GUI(void) {//�H���������骺��l�]�w
    //��������ܼ�
    bScanKeyTrigger     = 1;							//�Ұʫ��䱽�y
	KeyEvent_Shadow     = KEYEVENT_NO_EVENT;			//�M�ū���ƥ�v�l
	KeyEvent		    = KEYEVENT_NO_EVENT;			//�M�ū���ƥ�

    nFuntionIndex 	    = _Menu_EntryPoint_Index;		//�_�l�ާ@���
	menu_state 		    = 1;							//����l���A
	OpMode 			    = OpMode_StandBy;				//�]�w�t�Ϊ��B��Ҧ����ݾ����A
	OpModeF			    = 0;							//�M�ŹB��Ҧ��P��X��
	ModeSel_Action_F    = 0;                            //�M�żҦ��]�w����X��
	PVINV_ErrCode 	    = GUI_ErrCode_NO_ERROR;			//�M��PVINV�^�������~�X
	IBDC_ErrCode 	    = GUI_ErrCode_NO_ERROR;			//�M��IBDC�^�������~�X
	PVINV_WarningCode   = GUI_WarningCode_NO_Waring;	//�M��IBDC�^����ĵ�T�X
	IBDC_WarningCode    = GUI_WarningCode_NO_Waring;	//�M��IBDC�^����ĵ�T�X
	PVINV_Report        = GUI_Report_NoAvailable;       //�M��PVINV�^����T
	IBDC_Report         = GUI_Report_NoAvailable;       //�M��IBDC�^����T
	PV_PowerGeneration  = 0;                            //MPPT�o�q�q�]�w��0kW
	INV_PowerGeneration = 0;                            //INV�o�q�q�]�w��0kW
	IBDC_PowerGeneration= 0;                            //IBDC�o�q�q�]�w��0kW

	//��ܰ_�l�e��
	LCD_Display("TATUNG Smart INV", "-------> PowerOn");
	do_ParaSet_Done();	//�o���ѼơA�䤤OpMode_Enable=0��n����B�@

	//�B�zLED�����A
	LED_RED_OFF; LED_YELLOW_OFF; LED_GREEN_ON;
}

//�Τ��_�Ӷi����䪺���y�u�@
//�`�N�G���ઽ����KeyEvent�A�]������C�����_��sKeyEvent�A��L�t��
//      �֪���Ʒ����i��|�A���ܰʥ��A�q�ӨϨ�Ө�ƩΨ�L���L�k�o��
//      �s�����쪺KeyEvent�A�Ӱ��X�����T������
//      �ҥH�~�|�]�pKeyEvent_Shadow
__interrupt void cpu_timer0_isr(void) {
	 CpuTimer0.InterruptCount++;	//�L�q�A�ȬO���D���_���@��

	if (bScanKeyTrigger) {//�O�_�n�i�汽�y����H
	   KeyEvent_Shadow = ScanKey();		//�i�汽�y����
	   if (KeyEvent_Shadow != KEYEVENT_NO_EVENT)
		   bScanKeyTrigger = 0; //������䱽�y�A�������ƥ�Q�B�z����
   }

   PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;	//�A���Ұʤ��_
}

void Menu_EntryPoint(void) {//���i�J�I
	if (KeyEvent == KEYEVENT_POWER_ON){
		nFuntionIndex	= _Menu_ModeParaSel_Index;	//�������
		menu_state 		= 1;						//��l�ƿ�檬�A
	}
}

//LWG�G�������ѼҦ��M�Ѽƪ��]�w�\��
//menu_state = 1(��ܰ���Ҧ��ΰѼƳ]�w�Ҧ��^�B2�]��ܨֺ�Ҧ��^�B3�]��ܥR�q�Ҧ��^�B4�]��ܫݾ��Ҧ��^�B5�]��ܰѼƳ]�w�Ҧ��^
void Menu_ModeParaSel(void) {//�Ҧ��P�Ѽƿ�ܿ��
	const Uint32 Max_menu_state = 5;	//����榳��ӿﶵ

/* �e�\��
	switch (KeyEvent) {//�ھ�Key Event�ӽվ�menu_state
	case KEYEVENT_CANCEL:
	case KEYEVENT_POWER_OFF:	init_SI_GUI();												return;
	case KEYEVENT_UP:			menu_state--;												break;
	case KEYEVENT_DOWN:			menu_state++; 												break;
	case KEYEVENT_OK:			nFuntionIndex = (1 == menu_state)? _Menu_ModeSel_Index:_Menu_ParaSet_Index;	//�������
								menu_state = 1; 											return;
	default:																				break;
	}
*/
	//�������餤��menu_state�N����ܪ��Ҧ�
	switch (KeyEvent) {//�ھ�Key Event�ӽվ�menu_state
	case KEYEVENT_CANCEL:       menu_state = 1;     break;
	case KEYEVENT_POWER_OFF:    init_SI_GUI();      return;
	case KEYEVENT_GRID:         menu_state = 2;     break;
	case KEYEVENT_CHARGER:      menu_state = 3;     break;
	case KEYEVENT_STANDBY:      menu_state = 4;     break;
	case KEYEVENT_PARAMETER:    menu_state = 5;     break;
	case KEYEVENT_OK:           nFuntionIndex = (5 == menu_state)? _Menu_ParaSet_Index:_Menu_ModeSel_Index; //�������
	                            if (5 == menu_state) menu_state = 1;    return;
	default:                                        break;
	}
	//�B�zmenu_state�MKEYEVENT_CLEAR;
	if (0 == menu_state) 			 menu_state = Max_menu_state;
	if (Max_menu_state < menu_state) menu_state=1;

	switch (menu_state) {//��ܰT��
	case 1: LCD_Display("Sel  Oper/PARA","Press KEY ---> "); break;
	case 2:	LCD_Display("Do GRID  Mode?","Press OK or ESC"); break;
	case 3: LCD_Display("Do CHAR  Mode?","Press OK or ESC"); break;
	case 4: LCD_Display("Do STBY  Mode?","Press OK or ESC"); break;
	case 5: LCD_Display("Do PaSet Mode?","Press OK or ESC"); break;
	default: break;
	}
}

//menu_state = 1(��ܰ���Ҧ��ΰѼƳ]�w�Ҧ��^�B2�]��ܨֺ�Ҧ��^�B3�]��ܥR�q�Ҧ��^�B4�]��ܫݾ��Ҧ��^�B5�]��ܰѼƳ]�w�Ҧ��^
void Menu_ModeSel(void) {//�Ҧ���ܿ��:�����w�g��ܦn�F

    //���t�X�e�����Ҧ��W�d�A���s�վ�menu_state���ƾ�
    switch (menu_state) {//��ܰT��
    case 2: menu_state = 1;   break;  //�ֺ�Ҧ�
    case 3: menu_state = 2;   break;  //�R�q�Ҧ�
    case 4: menu_state = 3;   break;  //�ݾ��Ҧ�
    default:                  break;
    }
    Menu_ModeSel_Action();
    nFuntionIndex = _Menu_ModeParaSel_Index;  //�������
    menu_state      = 1;                      //��l�ƿ�檬�A
}
/*
void Menu_ModeSel(void) {//�Ҧ���ܿ��
	const Uint32 Max_menu_state = 4;	//����榳���ӿﶵ

	if (OpMode_CheckWarning < menu_state) {//�b�˵�ĵ�ܰT���ɡAmenu_state�|�Q�]�w��Max_menu_state+1�A�H�ϧO��
		switch (KeyEvent) {//�ھ�Key Event�ӽվ�menu_state
		case KEYEVENT_POWER_OFF:	init_SI_GUI();	return;
		case KEYEVENT_CANCEL:		menu_state = 1; return;
		default:					return;
		}
	}

	switch (KeyEvent) {//�ھ�Key Event�ӽվ�menu_state
	case KEYEVENT_POWER_OFF:	init_SI_GUI();	return;
	case KEYEVENT_UP:			menu_state--;	break;
	case KEYEVENT_DOWN:			menu_state++; break;
	case KEYEVENT_OK:			Menu_ModeSel_Action();	return; //OpMode = menu_state; do_ModeSet();
	case KEYEVENT_CANCEL:		menu_state = 1; nFuntionIndex = _Menu_ModeParaSel_Index; return;
	default:					break;
	}

	//�B�zmenu_state�MKEYEVENT_CLEAR;
	if (0 == menu_state) 			 menu_state = Max_menu_state;
	if (Max_menu_state < menu_state) menu_state=1;

	switch (menu_state) {//��ܰT���G�˵�ĵ�ܰT���n��b�̫�@�Ӫ��A
	case 1:	LCD_Display("*Grid Discharger",	" Grid Charger");	break;
	//case 2:	LCD_Display("*Grid Charger",	" Standalone");		break;
	//case 3:	LCD_Display("*Standalone",		" Check Warning");	break;
	case 2:   LCD_Display("*Grid Charger",    " StandBy");     break;
	case 3:   LCD_Display("*StandBy",      " Check Warning");  break;
	case 4:	LCD_Display("*Check Warning",	" Grid Discharger");break;
	default: 													break;
	}
}
*/

void Menu_ModeSel_Action(void) {//�˵�ĵ�ܰT���άO�]�w�B��Ҧ�..
    ModeSel_Action_F = 1;
    if (OpMode_CheckWarning == menu_state) {//�n�˵�ĵ�ܰT���ܡH
        if (PVINV_WarningCode >= PVINV_WARN_NUMBER-1)   PVINV_WarningCode = PVINV_WARN_NUMBER-1;
        if (IBDC_WarningCode  >= IBDC_WARN_NUMBER-1)    IBDC_WarningCode  = IBDC_WARN_NUMBER-1;
        LCD_Display(PVINV_WarnMsg[PVINV_ErrCode], IBDC_WarnMsg[IBDC_ErrCode]);
        menu_state = OpMode_CheckWarning + 1; //�T���u�n��ܤ@���Y�i�A�[1�O���F���n�A�i�J�����
        return;
    }
    //�]�w�B��Ҧ�
    OpMode = menu_state;
    /* ���Display_Msg�����
    switch (menu_state) {//��ܰT��
    case 1: LCD_Display("Grid Discharger ", "      Waiting");   break;  //�ݭn���@�ӹL��
    case 2: LCD_Display("Grid Charger    ", "      Waiting");   break;
    case 3: LCD_Display("StandBy         ", "      RUNNING");   break;
    default:                                                    break;
    }
    */
    switch (menu_state) {//��ܰT��
    case 1: Display_Msg("W  Grid ");    break;  //�����|�q��q��Ҧ��B��e���e�m�@�~
    case 2: Display_Msg("W  BatC ");    break;  //����R�q�q���Ҧ��B��e���e�m�@�~
    case 3: Display_Msg("R StandB");    break;  //����ݾ��Ҧ����B��
    default:                            break;
    }
    do_ModeSet();
}

void do_ModeSet() {//����Ҧ��]�w�����᪺�ʧ@
    Uint16 counter;
    unsigned short Imax_D_temp = Imax_D; //�p�G�OBoost Mode�A���]�wIBDC��X�q�y��0

    if (1 == OpMode) Imax_D = 0;        //�p�G�OBoost Mode�A�h���]�wIBDC��X�q�y��0
    if (3 == OpMode) OpMode = 0;        //�]��������Ҧ��A�Q�θӼҦ��A�R��Stand-bye�Ҧ�
    OpModeF = 0;    do_ParaSet_Done();              //�M�ŹB��Ҧ��P��X�СA���MPPT�MINVBDC�o���B��Ѽ�
    for (counter=0; counter < 30; counter++)        //����3s
        DELAY_US(100000L);                            //����100ms
    OpModeF = 1;    mailbox_send(GUI2CAN_MAX);  //�sMPPT�MINVBDC�̹B��Ҧ��A�Ұ�
// �����աA�������A���ݥ��}
    if (0 != OpMode) {//�D�ݾ��Ҧ��A�h������IBDC�MPVINV���^��)
        LED_YELLOW_ON; counter = 0;
        while (1) {
            DELAY_US(100000L);
            if ((1==PVINV_Report)&&(1==IBDC_Report)) {
                PVINV_Report = GUI_Report_NoAvailable;
                IBDC_Report = GUI_Report_NoAvailable;
                break;
            }
            if (10 == ++counter) {OpModeF = 0; OpMode = 0; break;} //1��L��A������^���A���^Stand-by�Ҧ�
        }
        Imax_D = Imax_D_temp; do_ParaSet_Done(); //�A�Ǥ@���Ѽ�

        if (0 == OpMode)    LCD_Display("Try Again or    ", "Call Service ");
        LED_YELLOW_OFF;
    }
 //
    /* ���Display_Msg�����
    if (1 == OpMode)    LCD_Display("Grid Discharger ", "      RUNNING");
    if (2 == OpMode)    LCD_Display("Grid Charger    ", "      RUNNING");
    */
    if (1 == OpMode)    Display_Msg("R  Grid ");
    if (2 == OpMode)    Display_Msg("R  BatC ");
}

void do_ParaSet_Done(void) {//�N�ѼƳz�LCAN Bus�o����MPPT�MInverter+BDC...
    Uint16 nMBXnbr;

    //change baud rate
    setupBaudRate(BaudRate);
    for (nMBXnbr=GUI2CAN_MIN; nMBXnbr<= GUI2CAN_MAX; nMBXnbr++) {
            mailbox_send(nMBXnbr);  //�o���Ѽ�
            DELAY_US(400L);
    }
}

//***�Ѽƣ�

void Menu_ParaSet(void) {//�ѼƳ]�w���
	unsigned short SI_Parameters_Shadow[ModbusAddrMax];
	unsigned short index;
	unsigned short data;
	//const Uint32 Max_menu_state = ModbusAddrMax;	//����榳ModbusAddrMax�ӿﶵ
	char ParaMsg[ModbusAddrMax][17] = {
		    //0123456789ABCDEF
			{" Imax_O = 14.0 A"},
			{" Vmin_B = 42.0 V"},
			{" Imax_C = 30.0 A"},
			{" Vabsor = 56.0 V"},
			{" Tabsor =  2.0 H"},
			{" Vfloat = 55.5 V"},
			{" Imax_D =  7.5 A"},
			{" LVP    =100.0 V"},
			{" VoutF  =    1  "},
			{" FoutF  =    1  "},
			{" ChargeF=    1  "},
			{" MD_ID  =    1  "},
			{" BaudRa =    5  "}
	};

	//1. �K�X�T�{
	if (!Password_Check()) {menu_state = 1; nFuntionIndex = _Menu_ModeParaSel_Index; return;}
	bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;

	//2. ��l��SI_Parameters_Shado
	for (index=0; index<ModbusAddrMax; index++) SI_Parameters_Shadow[index] = SI_Parameters[index];

	//3. �L�a�j��A����]�w�n�άO����
	while (1) {
		Uint16 menu_second = menu_state;

		//a. ��s��ܰT��
		if (ModbusAddrMax==menu_state) menu_second = 0;
		ParaMsg[menu_state-1][0] = '*'; ParaMsg[menu_second][0] = ' ';
		updateDisplayMsg(ParaMsg[menu_state-1], SI_Parameters_Shadow[menu_state-1], menu_state);
		updateDisplayMsg(ParaMsg[menu_second], SI_Parameters_Shadow[menu_second], menu_second+1);
		LCD_Display(ParaMsg[menu_state-1], ParaMsg[menu_second]);

		//b. //���s����ƥ�ܡH��s���A�M��ھ�Key Event�ӽվ�menu_state
		if (!bScanKeyTrigger) {KeyEvent = KeyEvent_Shadow;	KeyEvent_Shadow = KEYEVENT_NO_EVENT;}
		switch (KeyEvent) {
		case KEYEVENT_POWER_OFF:	init_SI_GUI();								return;
		case KEYEVENT_UP:			menu_state--;								break;
		case KEYEVENT_DOWN:			menu_state++;								break;
		case KEYEVENT_CANCEL:		menu_state = 1;
									nFuntionIndex = _Menu_ModeParaSel_Index; 	return;
		default:																break;
		}
		if (KEYEVENT_OK == KeyEvent) break;

		//c. �B�zmenu_state
		if (0 == menu_state)				menu_state = ModbusAddrMax;
		if (ModbusAddrMax < menu_state) 	menu_state=1;

		//d. �̾ګ���ƥ��s���
		data = SI_Parameters_Shadow[menu_state-1];
		switch (KeyEvent) {
		case KEYEVENT_LEFT:			data += 1; 							break;
		case KEYEVENT_RIGHT:		(data<=1)? data=0:data--; 			break;
		case KEYEVENT_LEFT_LONG:	data += 3; 							break;
		case KEYEVENT_RIGHT_LONG:	(data <= 3)? data=0:(data -= 3);	break;
		}
		if (KeyEvent != KEYEVENT_NO_EVENT) {bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;}

		//e. �T�{�b�W�U����
		if (data > SI_Parameters_MinMax[menu_state-1][1]) data = SI_Parameters_MinMax[menu_state-1][1];
		if (data < SI_Parameters_MinMax[menu_state-1][0]) data = SI_Parameters_MinMax[menu_state-1][0];
		//f. ��s
		SI_Parameters_Shadow[menu_state-1] = data;
	}

	//��s���ҳ]�w���ѼơA�M��o����MPPT�BInverter+IBDC
	for (index=0; index<ModbusAddrMax; index++)	SI_Parameters[index] = SI_Parameters_Shadow[index];
	do_ParaSet_Done();	menu_state = 1; nFuntionIndex = _Menu_ModeParaSel_Index;
}

//��s��ܰT��
void updateDisplayMsg(char* pmyMsg, unsigned short myData, unsigned short position) {
	unsigned short data;
	unsigned short curpos;

	curpos = 13; data = myData;
	*(pmyMsg+curpos) = '0'+ data%10; data = data/10; curpos--;
	if (position <= ModbusAddrMax-5) {//��T���ѪR��1�A�e���Ҭ�0.1
		*(pmyMsg+curpos)='.'; curpos--;
		if (0==data) {*(pmyMsg+curpos) = '0'+ data%10; curpos--;}
	}

	//if ((0==data)&&(position != ModbusAddrMax)) {*(pmyMsg+curpos) = '0'+ data%10; curpos--;}
	for (; curpos>8; curpos--) {
		if (0==data) *(pmyMsg+curpos) = ' ';
		else {*(pmyMsg+curpos) = '0'+ data%10; data = data/10;}
	}
}


//�K�X�T�{�G�����T�^��0�F�Ϥ��^��1
//Uint16  Password = 0x1234;		//�K�X
//Uint16  Password_Length = 4;		//�K�X����
//�W�� = 0x01�B�U�� = 0x02�B���� = 0x03�B�k�� = 0x04
Uint16 Password_Check(void) {
	char PasswordMsg[2][17] = {{"Password Check"}, {"-> "}};
	Uint16  myPassword = 0x00;
	Uint16	myPassword_Length = 0;

	//���}���䰻������
	bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;

	while (1) {//��J�K�X
		LCD_Display(PasswordMsg[0], PasswordMsg[1]);
		if (!bScanKeyTrigger) 	{KeyEvent = KeyEvent_Shadow;	KeyEvent_Shadow = KEYEVENT_NO_EVENT;}
		else					continue;

		switch (KeyEvent) {
		case KEYEVENT_POWER_OFF:	init_SI_GUI();	return 0;
		case KEYEVENT_UP: 			myPassword = myPassword<<4 | 0x01; myPassword_Length++; break;//<<4
		case KEYEVENT_DOWN:			myPassword = myPassword<<4 | 0x02; myPassword_Length++; break;
		case KEYEVENT_LEFT: 		myPassword = myPassword<<4 | 0x03; myPassword_Length++; break;
		case KEYEVENT_RIGHT:		myPassword = myPassword<<4 | 0x04; myPassword_Length++; break;
		case KEYEVENT_CANCEL:		bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT; 		return 0;
		}

		if (KeyEvent == KEYEVENT_OK) {
			if ((myPassword_Length==Password_Length) && (myPassword == Password)) {
				bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;
				return 1;	//�K�X���T
			}

			//�K�X���~���B�m
			LCD_Display(PasswordMsg[0], "Error,Try Again?");//�߰ݭn���n�~����աH
			bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;
			while (1) {
				if (!bScanKeyTrigger) 	{
					KeyEvent = KeyEvent_Shadow;	KeyEvent_Shadow = KEYEVENT_NO_EVENT;
					if (KeyEvent == KEYEVENT_OK) 		{bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT; break;}
					if (KeyEvent == KEYEVENT_POWER_OFF) {init_SI_GUI(); return 0;}
					if (KeyEvent == KEYEVENT_CANCEL) 	{bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT; return 0;}
				}
				bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;
				DELAY_US(400L); //while�j��ӧ֡A�L�k�A�ɱo����䵲�G�A�[�ө���A�T�O��
			}
			myPassword = 0x00; myPassword_Length = 0;			//��J�K�X�k�s
			PasswordMsg[1][3] = '\0';							//�M�ŬP��
			continue;
		}
		if (myPassword_Length < 14) {PasswordMsg[1][myPassword_Length+2] = '*'; PasswordMsg[1][myPassword_Length+3] = '\0';}
		if (KeyEvent != KEYEVENT_NO_EVENT) {bScanKeyTrigger = 1; KeyEvent = KEYEVENT_NO_EVENT;}
	}
}
/*
void do_ParaSet_Done(void) {//�N�ѼƳz�LCAN Bus�o����MPPT�MInverter+BDC...

}
*/


/*org
 void do_ModeSet() {//����Ҧ��]�w�����᪺�ʧ@
    Uint16 counter;
    unsigned short Imax_D_temp = Imax_D; //�p�G�OBoost Mode�A���]�wIBDC��X�q�y��0

    if (1 == OpMode) Imax_D = 0;        //�p�G�OBoost Mode�A�h���]�wIBDC��X�q�y��0
    OpModeF = 0;    do_ParaSet_Done();              //�M�ŹB��Ҧ��P��X�СA���MPPT�MINVBDC�o���B��Ѽ�
    for (counter=0; counter < 30; counter++)        //����3s
        DELAY_US(100000L);                            //����100ms
    OpModeF = 1;    mailbox_send(GUI2CAN_MAX);  //�sMPPT�MINVBDC�̹B��Ҧ��A�Ұ�

    if (1 == OpMode) {//�p�G�OBoost Mode�A�h������IBDC�MPVINV���^��)
        LED_YELLOW_ON;
        while (1) {
            DELAY_US(100000L);
            if ((1==PVINV_Report)&&(1==IBDC_Report)) {
                PVINV_Report = GUI_Report_NoAvailable;
                IBDC_Report = GUI_Report_NoAvailable;
                break;
            }
        }
        Imax_D = Imax_D_temp; do_ParaSet_Done(); //�A�Ǥ@���Ѽ�
        LCD_Display("Grid Discharger ", "      RUNNING");
        LED_YELLOW_OFF;
    }
}
 */
//===========================================================================
// No more.
//===========================================================================

  • Hi Wen-Gou,

    Thank you for providing a detailed question.  What you are seeing is normal behavior when the SPI module drives the CSn pin.  To achieve what you need, you need to configure the CSn pin as a GPIO and add instructions in your code to have the MCU set the GPIO pin high and low.  Your code would look something like this:

    // Init

    Setup SPI pin mux (enable all SPI pins)

    Setup GPIO pin mux (configure CSn as GPIO)

    Set CSn high (write directly to GPIO register)

    ...

    // EEPROM write

    Set CSn low (write directly to GPIO register)

    Transfer N bytes using SPI

    Set CSn high (write directly to GPIO register)

    I hope this helps!