문제1) 아래의 함수를 개선하시오.
void DisplayInfo_set(U8 TestNum)
{
switch(TestNum) {
case eTCh :
Put_Tx_U8('C');
Put_Tx_U8('H');
Put_Tx_U8(' ');
Put_Tx_U8(' ');
break;
case eTDisplaySWVer :
Put_Tx_U8('D');
Put_Tx_U8('I');
Put_Tx_U8('S');
Put_Tx_U8('W');
break;
case eTDisplayHWVer :
Put_Tx_U8('D');
Put_Tx_U8('I');
Put_Tx_U8('H');
Put_Tx_U8('W');
break;
case eTInputFWVer :
Put_Tx_U8('I');
Put_Tx_U8('N');
Put_Tx_U8('F');
Put_Tx_U8('W');
break;
default :
break;
}
}
문제2) 아래의 함수를 개선하시오.
void tsn_resp(void)
{
U16 ch;
U8 i, testNum, INtype, IsCali;
testNum = *pCOMtbuf;
pFTest.uData.pU16 = NULL;
pFTest.TestNum = 100;
INtype = 0;
IsCali = 0;
switch(testNum) {
case eTCh :
pFTest.uData.pU8 = &pFTest.Ch;
break;
case eTSpec :
pFTest.uData.pS16 = &buf_SYSSPEC;
MMI_no = MMI_CAL_SET1;
break;
case eTDisplaySWVer :
case eTDisplayHWVer :
pFTest.uData.pU8 = ¶_DISPLAY_VER[testNum & 0x01][0];
MMI_no = MMI_CAL_MENU;
break;
case eTInputFWVer :
case eTInputHWVer :
pFTest.uData.pU8 = ¶_INPUT_VER[testNum & 0x01][0];
MMI_no = MMI_CAL_MENU;
break;
case eTI_OFWVer :
case eTI_OHWVer :
pFTest.uData.pU8 = ¶_RELAY_VER[testNum & 0x01][0];
MMI_no = MMI_CAL_MENU;
break;
case eTCOMChk :
pFTest.uData.pU8 = &flag_COMM_ERROR[0];
MMI_no = MMI_CAL_SET2_2;
break;
case eTFRAMChk :
flag_CAL_FRAM_TST = FM24CL64B_Test();
pFTest.uData.pU8 = &flag_CAL_FRAM_TST;
MMI_no = MMI_CAL_SET2_2;
break;
case eTSDChk :
flag_CAL_SD_TST = SDCard_Test();
pFTest.uData.pU8 = &flag_CAL_SD_TST;
MMI_no = MMI_CAL_SET2_2;
break;
case eTUSBChk :
flag_CAL_USB_TST = USB_Test();
pFTest.uData.pU8 = &flag_CAL_USB_TST;
MMI_no = MMI_CAL_SET2_2;
break;
case eTDIChk :
pFTest.uData.pU8 = &DI_status;
MMI_no = MMI_CAL_SET2_4;
break;
case eTDOChk :
pFTest.uData.pS16 = &DO_STAT;
DO_AutoMode = 0;
flag_RLY = 0;
MMI_no = MMI_CAL_SET2_5;
break;
case eTRJCInputChk :
pFTest.uData.pS16 = &NRJC[0];
for(i=0;i<12;i++) {
para_INTYPE[i]=7;
para_UNIT[i]=0;
IN_Init(i);
}
MMI_no = MMI_CAL_SET4_1;
break;
case eTCali30mvZero :
case eTCali30mvSpan :
IsCali = 1;
INtype = 11;
CAL_no = ZERO_TC50;
MMI_no = MMI_CAL_SET3_1;
break;
case eTCali150mvZero :
case eTCali150mvSpan :
IsCali = 1;
INtype = 7;
CAL_no = ZERO_TC10;
MMI_no = MMI_CAL_SET3_2;
break;
case eTCali17_5vZero :
case eTCali17_5vSpan :
IsCali = 1;
INtype = 21;
CAL_no = ZERO_DCV10;
MMI_no = MMI_CAL_SET3_3;
break;
case eTCali130vZero :
case eTCali130vSpan :
IsCali = 1;
INtype = 22;
CAL_no = ZERO_DCV1;
MMI_no = MMI_CAL_SET3_4;
break;
case eTCali150ohmZero :
case eTCali150ohmSpan :
IsCali = 1;
INtype = 2;
CAL_no = ZERO_RTD50;
MMI_no = MMI_CAL_SET3_5;
break;
case eTCali330ohmZero :
case eTCali330ohmSpan :
IsCali = 1;
INtype = 1;
CAL_no = ZERO_RTD10;
MMI_no = MMI_CAL_SET3_6;
break;
case eTCalRJCBias :
pFTest.uData.pS16 = &RJC_bias_input[0];
INtype = 7;
MMI_no = MMI_CAL_SET4_5;
break;
case eTPARAInit :
case eTINTMEMInit :
case eTRTCInit :
case eTCaliSave :
MMI_no = MMI_CAL_SET5;
break;
case eTRTDPT1Chk :
pFTest.uData.pS16 = &NPV[0];
flag_cal_ch_sel = 0;
INtype = 1;
MMI_no = MMI_CAL_SET4_2;
break;
case eTRTDPT2Chk :
pFTest.uData.pS16 = &NPV[0];
flag_cal_ch_sel = 1;
INtype = 2;
MMI_no = MMI_CAL_SET4_2;
break;
case eTVDC5VChk :
pFTest.uData.pS16 = &NPV[0];
flag_cal_ch_sel = 0;
INtype = 21;
MMI_no = MMI_CAL_SET4_3;
break;
case eTVDC30VChk :
pFTest.uData.pS16 = &NPV[0];
flag_cal_ch_sel = 1;
INtype = 22;
MMI_no = MMI_CAL_SET4_3;
break;
case eTTCK1Chk :
pFTest.uData.pS16 = &NTC[0];
flag_cal_ch_sel = 0;
INtype = 7;
MMI_no = MMI_CAL_SET4_4;
break;
case eTTCRChk :
pFTest.uData.pS16 = &NTC[0];
flag_cal_ch_sel = 1;
INtype = 11;
MMI_no = MMI_CAL_SET4_4;
break;
default :
cmd_err1 = ECODE_OTHER;
break;
}
if(!cmd_err1) pFTest.TestNum = testNum;
else {
if(IsCali) {
if(testNum & 0x01) pFTest.uData.pU16 = &Cal_span[0];
else pFTest.uData.pU16 = &Cal_zero[0];
}
if(INtype) {
for(i=0;i<12;i++) {
para_INTYPE[i] = INtype;
if(testNum == eTVDC5VChk || testNum == eTVDC30VChk) IN_Init_special(i);
else {
para_UNIT[i] = 0;
IN_Init(i);
}
}
}
}
}
정답1)
typedef struct stDisplay_Map_tag {
U8 TestNum;
const U8* displayStr;
}stDisplay_Map;
static const stDisplay_Map aDisplay_table[] = {
{eTCh, "CH"},
{eTDisplaySWVer, "DISW"},
{eTDisplayHWVer, "DIHW"},
{eTInputFWVer, "INFW"}
};
void DisplayInfo_set(U8 TestNum)
{
U8 i, tableSize;
const U8* str;
tableSize = sizeof(aDisplay_table) / sizeof(stDisplay_Map[0]);
for(i=0; i<tableSize; i++) {
if(aDisplay_table[i].TestNum == TestNum) {
str = aDisplay_table[i].displayStr;
while(*str) Put_Tx_U8(*str++);
break;
}
}
}
정답2)
static const TestCaseInfo_t testTable[] = {
{ eTCh, &pFTest.TestNum, DATA_U8, 0, 0, 0, 0 },
{ eTSpec, &buf_SYSSPEC, DATA_S16, 0, MMI_CAL_SET1, 0, 0 },
{ eTDisplaySWVer, ¶_DISPLAY_VER[0][0], DATA_U8, 0, MMI_CAL_MENU, 0, 0 },
{ eTDisplayHWVer, ¶_DISPLAY_VER[1][0], DATA_U8, 0, MMI_CAL_MENU, 0, 0 },
{ eTInputFWVer, ¶_INPUT_VER[0][0], DATA_U8, 0, MMI_CAL_MENU, 0, 0 },
{ eTInputHWVer, ¶_INPUT_VER[1][0], DATA_U8, 0, MMI_CAL_MENU, 0, 0 },
{ eTI_OFWVer, ¶_RELAY_VER[0][0], DATA_U8, 0, MMI_CAL_MENU, 0, 0 },
{ eTI_OHWVer, ¶_RELAY_VER[1][0], DATA_U8, 0, MMI_CAL_MENU, 0, 0 },
{ eTCOMChk, &flag_COMM_ERROR[0], DATA_U8, 0, MMI_CAL_SET2_2, 0, 0 },
{ eTFRAMChk, NULL, DATA_U8, 0, MMI_CAL_SET2_2, 0, 0 },
{ eTSDChk, NULL, DATA_U8, 0, MMI_CAL_SET2_2, 0, 0 },
{ eTUSBChk, NULL, DATA_U8, 0, MMI_CAL_SET2_2, 0, 0 },
{ eTDIChk, &DI_status, DATA_U8, 0, MMI_CAL_SET2_4, 0, 0 },
{ eTDOChk, &DO_STAT, DATA_S16, 0, MMI_CAL_SET2_5, 0, 0 },
{ eTRJCInputChk, &NRJC[0], DATA_S16, 7, MMI_CAL_SET4_1, 0, 0 },
{ eTCalRJCBias, &RJC_bias_input[0], DATA_S16, 7, MMI_CAL_SET4_5, 0, 0 },
{ eTRTDPT1Chk, &NPV[0], DATA_S16, 1, MMI_CAL_SET4_2, 0, 0 },
{ eTRTDPT2Chk, &NPV[0], DATA_S16, 2, MMI_CAL_SET4_2, 0, 1 },
{ eTVDC5VChk, &NPV[0], DATA_S16, 21, MMI_CAL_SET4_3, 0, 0 },
{ eTVDC30VChk, &NPV[0], DATA_S16, 22, MMI_CAL_SET4_3, 0, 1 },
{ eTTCK1Chk, &NTC[0], DATA_S16, 7, MMI_CAL_SET4_4, 0, 0 },
{ eTTCRChk, &NTC[0], DATA_S16, 11, MMI_CAL_SET4_4, 0, 1 },
// Calibration cases can be handled separately
};
void tsn_resp(void) {
uint8_t testNum = *pCOMtbuf;
pFTest.uData.pU16 = NULL;
pFTest.TestNum = 100;
cmd_err1 = 0;
for (int i = 0; i < sizeof(testTable) / sizeof(testTable[0]); i++) {
if (testTable[i].testNum == testNum) {
switch (testTable[i].dataType) {
case DATA_U8: pFTest.uData.pU8 = (uint8_t *)testTable[i].dataPtr; break;
case DATA_S16: pFTest.uData.pS16 = (int16_t *)testTable[i].dataPtr; break;
case DATA_U16: pFTest.uData.pU16 = (uint16_t *)testTable[i].dataPtr; break;
}
MMI_no = testTable[i].mmiNo;
flag_cal_ch_sel = testTable[i].chSel;
if (testNum == eTFRAMChk) flag_CAL_FRAM_TST = FM24CL64B_Test();
else if (testNum == eTSDChk) flag_CAL_SD_TST = SDCard_Test();
else if (testNum == eTUSBChk) flag_CAL_USB_TST = USB_Test();
if (testTable[i].inType) {
for (int ch = 0; ch < 12; ch++) {
para_INTYPE[ch] = testTable[i].inType;
if (testNum == eTVDC5VChk || testNum == eTVDC30VChk) IN_Init_special(ch);
else {
para_UNIT[ch] = 0;
IN_Init(ch);
}
}
}
pFTest.TestNum = testNum;
return;
}
}
// Calibration special case 처리 생략 (원하면 추가 가능)
cmd_err1 = ECODE_OTHER;
}
질문1) aDisplay_table을 DisplayInfo_set 함수 내부에 선언하면 메모리 공간을 더 아낄 수 있는데 그렇게 하지 않은 이유(2가지)는 무엇인가?
답변1)
aDisplay_table을 DisplayInfo_set 함수 내부에 선언하면 함수가 호출될 때마다 테이블이 스택 메모리(RAM)에 생성되고, 함수가 끝나면 소멸된다. 이 방식은 메모리를 아끼는 것처럼 보일 수 있지만, 스택은 크기가 제한적이기 때문에 아래와 같은 2가지 문제가 발생할 수 있다.
1. 스택 오버플로우
aDisplay_table처럼 크기가 큰 상수 테이블을 함수 내부에 선언하면, 여러 함수가 동시에 호출될 때 스택 메모리 초과로 프로그램이 오작동할 수 있다.
2. 불필요한 반복 생성
테이블은 고정된 상수이기 때문에 함수가 호출될 때마다 반복해서 생성할 필요가 없다. 매번 생성하면 오히려 효율이 떨어진다.
따라서 aDisplay_table을 함수 바깥에 정적(static) 또는 상수(const) 전역 변수로 선언하면, ROM 영역에 한 번만 할당되고 스택 공간을 절약할 수 있다. 이런 방식이 임베디드 시스템에서 메모리 최적화에 더 적합하다.
<추가 자료>
https://powerdeng.tistory.com/263
[C 개념] 메모리 구조
powerdeng.tistory.com
https://powerdeng.tistory.com/264
[C 개념] ROM 종류와 특징
종류설명재작성가능 여부사용 예시Mask ROM제조 시 내용이 고정되어 변경 불가.불가능대량생산된 게임 카트리지PROM(Programmable ROM)한 번만 프로그래밍 가능1회 가능과거의 하드웨어 설정 값 저장EPR
powerdeng.tistory.com