앞의 문서에 이어지는 내용으로서 타겟보드에 S/W 가 최소한 조건을 만들기 위한 부팅을 하고나서 어떤 루틴이 수행되는지 알아본다.
부팅까지 마무리 되면,
(void) ST_GetClockInfo(&ST_ClockInfo);
5517 의 경우 하드웨어적으로 27 MHz 의 입력신호를 받는다. 위의 함수는 S/W 적으로 레지스터를 27 MHz 으로 설정한다.
여기서 선언된 'ST_ClockInfo' 는 I2C, TSMUX, UART 를 초기화하는 데, 사용한다. 여기서 I2C 의 경우는 동기식 시리얼 통신방식이다.(SSC)
UART 는 비동기식 시리얼 통신방식이다.(ASSC)
내 생각에는 각각의 디바이스마다 속도가 다르고, 클럭이 다르기 때문이지 아닐까 한다. 또한 이들 디바이스들은 모두 동기식(synchronous) 또는 비동기식(asynchronous)으로 동작한다.
실제로 위의 루틴을 막아놓고 프로그램을 실행해봤다. 결과는 제대로된 실행을 못했다. 프로그램이 수행되는 데, 많은 시간이 걸렸다.
PIO 는 가장 다양하게 쓰이는 디바이스 중에 하나다. 5517 은 총 48 개의 PIO 를 지원한다. 현재, 이 것은 POD, 7020, 튜너, I2C, UART 등에서 거의 대부분 쓰여지고 있다. 물론 가장 먼저 PIO 초기화가 이루어져야 사용 가능하다.
ST_DeviceName_t PIO_DeviceName[] = {"PIO0","PIO1","PIO2","PIO3","PIO4","PIO5"}; /* local variables --------------------------------------------------------- */ static STPIO_InitParams_t STPIO_InitParams[PIO_PORTS] = { { (U32*) PIO_0_BASE_ADDRESS, PIO_0_INTERRUPT, PIO_0_INTERRUPT_LEVEL }, // 각 PIO 의 주소, 인터럽트 번호 등록, 인터럽트 레벨 { (U32*) PIO_1_BASE_ADDRESS, PIO_1_INTERRUPT, PIO_1_INTERRUPT_LEVEL }, { (U32*) PIO_2_BASE_ADDRESS, PIO_2_INTERRUPT, PIO_2_INTERRUPT_LEVEL }, { (U32*) PIO_3_BASE_ADDRESS, PIO_3_INTERRUPT, PIO_3_INTERRUPT_LEVEL }, { (U32*) PIO_4_BASE_ADDRESS, PIO_4_INTERRUPT, PIO_4_INTERRUPT_LEVEL }, #if PIO_PORTS > 5 { (U32*) PIO_5_BASE_ADDRESS, PIO_5_INTERRUPT, PIO_5_INTERRUPT_LEVEL } #endif }; /* Functions -------------------------------------------------------------- */ ST_ErrorCode_t PIO_Setup( void ) { ST_ErrorCode_t ST_ErrorCode; int instance; for (instance = 0; instance < PIO_PORTS; instance++) { STPIO_InitParams[instance].DriverPartition = SystemPartition; ST_ErrorCode = STPIO_Init( PIO_DeviceName[instance], &STPIO_InitParams[instance] ); #ifdef REPORT_TO_CONSOLE printf("PIO_Setup(%s)=", PIO_DeviceName[instance]); if (ST_ErrorCode != ST_NO_ERROR) printf("%s\n", GetErrorText(ST_ErrorCode) ); else printf("%s\n", STPIO_GetRevision() ); #endif }
총 PIO 핀들을 루프를 돌면서 초기화 한다. 인터럽트 레벨의 숫자가 높을 수록 높다.
UART 는 하드웨어 상으로 보면, PIO 이다. 다시 말하자면, PIO 보다 좀더 상위의 디바이스라고 보면 된다. 그래서 UART 를 초기화 하기 전에 반드시 PIO 를 초기화 해야 한다.
ST_ErrorCode_t UART_Setup(void) { ST_ErrorCode_t ST_ErrorCode = ST_NO_ERROR; U8 InitList[] = { DATA_UART_DEV, MODEM_UART_DEV, SC0_UART_DEV, SC1_UART_DEV, UART_END_OF_LIST }; 각각의 ASC 를 초기화 U8 index; for ( index = 0; InitList[index] != UART_END_OF_LIST; index++ ) { ST_ErrorCode |= uart_init(InitList[index]); } // ST_ErrorCode = uart_init(3); return ( ST_ErrorCode ); }
위에서는 각각의 모든 ASC 를 초기화 하고 있다. 하지만, 모든 PIO 를 UART 로 사용하지는 않을 것이기 때문에 꼭 필요한 ASC 만 초기화해야 한다.
만약 다른 용도로 쓰고 있는 PIO 를 UART 가 초기화하면, 나중에 PIO 콘트롤을 못한다.
static ST_ErrorCode_t uart_init(int instance) { ST_ErrorCode_t ST_ErrorCode = ST_NO_ERROR; STUART_InitParams_t STUART_InitParams; STUART_Params_t STUART_Params; /* Common Init Parameters */ STUART_InitParams.DriverPartition = SystemPartition; STUART_InitParams.ClockFrequency = ST_ClockInfo.CommsBlock; STUART_InitParams.SwFIFOEnable = TRUE; STUART_InitParams.FIFOLength = 256; STUART_InitParams.RXD.PortName[0] = '\0'; STUART_InitParams.TXD.PortName[0] = '\0'; STUART_InitParams.RTS.PortName[0] = '\0'; STUART_InitParams.CTS.PortName[0] = '\0'; #ifdef REPORT_TO_CONSOLE printf("STUART_Setup(%s/", UART_DeviceName[instance] ); #endif switch(instance) { case DATA_UART_DEV: #ifdef REPORT_TO_CONSOLE printf("DATA_UART_DEV)="); #endif /* set default values */ STUART_Params.RxMode.BaudRate = 4800; STUART_Params.RxMode.DataBits = STUART_8BITS_NO_PARITY; STUART_Params.RxMode.StopBits = STUART_STOP_1_0; STUART_Params.RxMode.FlowControl = STUART_NO_FLOW_CONTROL; STUART_Params.RxMode.TermString = NULL; STUART_Params.RxMode.TimeOut = 0; /* As short as possible */ STUART_Params.RxMode.NotifyFunction = NULL; /* No callback */ STUART_Params.TxMode.BaudRate = 4800; STUART_Params.TxMode.DataBits = STUART_8BITS_NO_PARITY; STUART_Params.TxMode.StopBits = STUART_STOP_1_0; STUART_Params.TxMode.FlowControl = STUART_NO_FLOW_CONTROL; STUART_Params.TxMode.TermString = NULL; STUART_Params.TxMode.TimeOut = 0; /* No time-out */ STUART_Params.TxMode.NotifyFunction = NULL; /* No callback */ STUART_Params.SmartCardModeEnabled = FALSE; STUART_Params.GuardTime = 0; STUART_Params.NACKSignalDisabled = FALSE; STUART_Params.HWFifoDisabled = FALSE; /* Initialize DATA Uart */ STUART_InitParams.UARTType = ASC_DEVICE_TYPE; STUART_InitParams.DefaultParams = &STUART_Params; STUART_InitParams.BaseAddress = (U32 *)DATA_UART_BASE_ADDRESS; STUART_InitParams.InterruptNumber = DATA_UART_INTERRUPT; STUART_InitParams.InterruptLevel = DATA_UART_INTERRUPT_LEVEL; STUART_InitParams.RXD.BitMask = DATA_UART_RXD_BIT; STUART_InitParams.TXD.BitMask = DATA_UART_TXD_BIT; STUART_InitParams.RTS.BitMask = DATA_UART_RTS_BIT; STUART_InitParams.CTS.BitMask = DATA_UART_CTS_BIT; strcpy(STUART_InitParams.RXD.PortName, PIO_DeviceName[DATA_UART_RXD_DEV]); strcpy(STUART_InitParams.TXD.PortName, PIO_DeviceName[DATA_UART_TXD_DEV]); strcpy(STUART_InitParams.RTS.PortName, PIO_DeviceName[DATA_UART_RTS_DEV]); strcpy(STUART_InitParams.CTS.PortName, PIO_DeviceName[DATA_UART_CTS_DEV]); break;
위는 UART 를 초기화할 때, 필요한 세팅값을 설정해주는 부분이다.
TBX 는 한마디로 printf 이다. 출력문을 DCU 또는 UART 로 내보낼 것인지 초기화할 때, 선택할 수 있다.
ST_ErrorCode_t TBX_Setup(void) { ST_ErrorCode_t ST_ErrorCode = ST_NO_ERROR; STTBX_InitParams_t STTBX_InitParams; memset(&STTBX_InitParams, '\0', sizeof( STTBX_InitParams_t ) ); STTBX_InitParams.SupportedDevices = STTBX_DEVICE_DCU | STTBX_DEVICE_UART; STTBX_InitParams.DefaultOutputDevice = STTBX_DEVICE_UART; <--- 이 부분이 선택 가능 STTBX_InitParams.DefaultInputDevice = STTBX_DEVICE_UART; <--- 이 부분이 선택 가능 STTBX_InitParams.CPUPartition_p = SystemPartition; strcpy(STTBX_InitParams.UartDeviceName, UART_DeviceName[2]);//FOR BLICK TBX_UART_DEVICE]); ST_ErrorCode = STTBX_Init(TBX_DeviceName, &STTBX_InitParams ); #ifdef REPORT_TO_CONSOLE printf("TBX_Setup(%s)=", TBX_DeviceName); if (ST_ErrorCode != ST_NO_ERROR) printf("%s\n", GetErrorText(ST_ErrorCode) ); else printf("%s\n", STTBX_GetRevision() ); #endif return ( ST_ErrorCode ); }
EVT 는 EVENT 의 줄임말이다. 이벤트는 어떤 특별한 일(?)이 발생했을 때, 지정된 동작대로 수행하도록 하는 일종의 인터럽트 루틴과 같은 것이다.
ST_ErrorCode_t EVT_Setup(void) { ST_ErrorCode_t ST_ErrorCode; STEVT_InitParams_t STEVT_InitParams; STEVT_OpenParams_t STEVT_OpenParams; int instance; memset(&STEVT_InitParams, '\0', sizeof( STEVT_InitParams_t ) ); memset(&STEVT_OpenParams, '\0', sizeof( STEVT_OpenParams_t ) ); for(instance = 0; instance < EVT_INST; instance++ ) { STEVT_InitParams.EventMaxNum = 100; // 사용 가능한 갯수 지정 STEVT_InitParams.ConnectMaxNum = 20; STEVT_InitParams.SubscrMaxNum = 150; STEVT_InitParams.MemoryPartition = SystemPartition; STTBX_Print(("EVT_Setup(%s)=", EVT_DeviceName[instance] )); ST_ErrorCode = STEVT_Init(EVT_DeviceName[instance], &STEVT_InitParams); if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); } STTBX_Print(("%s\n", STEVT_GetRevision() )); STTBX_Print(("EVT_Open=")); ST_ErrorCode = STEVT_Open(EVT_DeviceName[instance], &STEVT_OpenParams, &EVT_Handle[instance] ); STTBX_Print(("%s\n", GetErrorText(ST_ErrorCode) )); if (ST_ErrorCode != ST_NO_ERROR) return( ST_ErrorCode ); } /* for(instance) ;) */ return( ST_ErrorCode ); }
STEVT 의 경우, 초기화(init) 하면서, 바로 OPEN 시킨다. 그리고나서 STEVT_SubscribeDeviceEvent() 함수를 사용해서 이벤트를 등록한다. 이에 대한 설명은 관련 문서를 참고 하기 바란다.
ST 에서는 UART 와 I2C 같은 동기 또는 비동기적으로 움직이는 디바이스들에 대응하기 위해서 동기식의 경우에는 SSC 라는 포트(SSC0, SSC1)를 만들었다. 5517 에서는 총 2 개가 있다.
I2C 역시 밑으로는 PIO 를 사용하기 때문에, 먼저 PIO 초기화가 이루어져야 한다.
ST_ErrorCode_t I2C_Setup(void) { ST_ErrorCode_t ST_ErrorCode; STI2C_InitParams_t STI2C_InitParams; memset(&STI2C_InitParams, '\0', sizeof(STI2C_InitParams_t) ); /* back I2C bus */ STI2C_InitParams.BaseAddress = (U32 *)SSC_0_BASE_ADDRESS; // SSC0 레지스터 주소 STI2C_InitParams.InterruptNumber = SSC_0_INTERRUPT; // 인터럽트 설정 STI2C_InitParams.InterruptLevel = SSC_0_INTERRUPT_LEVEL; STI2C_InitParams.PIOforSDA.BitMask = PIO_FOR_SSC0_SDA; // SDA 로 사용할 PIO 설정 STI2C_InitParams.PIOforSCL.BitMask = PIO_FOR_SSC0_SCL; // SCL 로 사용할 PIO 설정 STI2C_InitParams.MasterSlave = STI2C_MASTER; // MASTER or SLAVE STI2C_InitParams.BaudRate = STI2C_RATE_NORMAL; // 속도 설정 STI2C_InitParams.MaxHandles = 8; STI2C_InitParams.ClockFrequency = ST_ClockInfo.CommsBlock; // 동기식이기 때문에, ST CLOCK 사용 STI2C_InitParams.DriverPartition = SystemPartition; strcpy(STI2C_InitParams.PIOforSDA.PortName, PIO_DeviceName[BACK_PIO]); strcpy(STI2C_InitParams.PIOforSCL.PortName, PIO_DeviceName[BACK_PIO]); STTBX_Print(("I2C_Setup(%s)=", I2C_DeviceName[I2C_3125_SC0] )); ST_ErrorCode = STI2C_Init(I2C_DeviceName[I2C_3125_SC0], &STI2C_InitParams); if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("%s\n", GetErrorText(ST_ErrorCode) )); } else { STTBX_Print(("%s\n", STI2C_GetRevision() )); } ... ... ST_ErrorCode = STI2C_Init(I2C_DeviceName[I2C_TUNER_SC1], &STI2C_InitParams); ... ...
현재 DAC5000 에서는 EEPROM, DVI, 3125 TUNNER, LG VSB TUNNER 를 I2C 로 사용하고 있다. 각각 SSC0 와 SSC1 을 사용하고 있다.
STCFG 는 5517 의 특정 레지스터 세팅하는 역할이다. 여기에서의 주된 세팅은 바로, Video, Audio, Sub-Picture Decoder 의 초기화이다.
ST_ErrorCode_t CFG_Setup(void) { ST_ErrorCode_t ST_ErrorCode = ST_NO_ERROR; STCFG_InitParams_t STCFG_InitParams; /* [31:25] Reserved */ // IRDA_ASC_RX_DATA_IN_EN, UHF_IN_EN, RC_IRDA_DATA_IN_EN 1 로 세팅 STSYS_WriteRegDev32LE(CONFIG_CONTROL_D, STSYS_ReadRegDev32LE(CONFIG_CONTROL_D) | 0x1E00000 ); /* [14] CONFIG_AUDIFREMAP_OVERRIDE 0:remapping 1:no remapping (access audio interface registers) */ STSYS_WriteRegDev32LE(CONFIG_CONTROL_E, STSYS_ReadRegDev32LE(CONFIG_CONTROL_E) | 0x00004000 ); /* [15] CONFIG_IRDACTRL_DIN_DISABLE Always set to 1 */ STSYS_WriteRegDev32LE(CONFIG_CONTROL_E, STSYS_ReadRegDev32LE(CONFIG_CONTROL_E) | 0x00008000 ); /* [16] CONFIG_IRB_UART2RXD_BYPASS 0:IRB to UART2RXD 1:PIO4[3] to UART2 directly */ // PIO4[3] 에 UART 연결 STSYS_WriteRegDev32LE(CONFIG_CONTROL_E, STSYS_ReadRegDev32LE(CONFIG_CONTROL_E) | 0x00010000 ); /* Bypass IrDA Control to allow ASC TX output */ // IRDA 데이터를 모두 TX 로 보냄 STSYS_WriteRegDev16LE(0x201150d0, 0x01); /* this is to allow correct access to MPEG reg. Note that 32bits write access is mandatory */ // 5517 데이터 시트에는 없는 주소 STSYS_WriteRegDev32LE(0x5000, 0x00077000); STCFG_InitParams.DeviceType = STCFG_DEVICE_5517; STCFG_InitParams.Partition_p = SystemPartition; STCFG_InitParams.BaseAddress_p = (U32*)ST5517_CFG_BASE_ADDRESS;
위에서 세팅하는 레지스터는 5517 데이터 시트의 Padlogic 부분이다. 내가 생각하기에 시스템 전반적인 세팅을 건드리는 것 같다.
다음은 A/V Decoder 를 초기화하는 부분이다.
/* --- PTI --- */ ST_ErrorCode = STCFG_CallCmd(CFG_Handle, STCFG_CMD_PTI_CDREQ_CONNECT, STCFG_PTI_A, STCFG_PTI_CDIN_0, STCFG_CDREQ_VIDEO_INT ); // Main Vedio Decoder 초기화 if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("STCFG_Call(STCFG_CDREQ_VIDEO_INT)=%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); } ST_ErrorCode = STCFG_CallCmd(CFG_Handle, STCFG_CMD_PTI_CDREQ_CONNECT, STCFG_PTI_A, STCFG_PTI_CDIN_0, STCFG_CDREQ_AUDIO_INT ); // Audio Decoder 초기화 if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("STCFG_Call(STCFG_CDREQ_AUDIO_INT)=%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); } ST_ErrorCode = STCFG_CallCmd(CFG_Handle, STCFG_CMD_PTI_CDREQ_CONNECT, STCFG_PTI_A, STCFG_PTI_CDIN_0, STCFG_CDREQ_SUBP_INT ); // Sub-Picture Decoder 초기화 if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("STCFG_Call(STCFG_CDREQ_SUBP_INT)=%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); } /* --- VIDEO --- */ ST_ErrorCode = STCFG_CallCmd(CFG_Handle, STCFG_CMD_VIDEO_ENABLE, STCFG_VIDEO_DAC_ENABLE); // Enable Video Decoder if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("STCFG_Call(STCFG_VIDEO_DAC_ENABLE)=%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); } /* --- AUDIO --- */ ST_ErrorCode = STCFG_CallCmd(CFG_Handle, STCFG_CMD_AUDIO_ENABLE, STCFG_AUDIO_DAC_POWER_OFF); // Power Down Audio DAC if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("STCFG_Call(STCFG_AUDIO_DAC_POWER_OFF)=%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); } /* --- PIO --- */ ST_ErrorCode = STCFG_CallCmd(CFG_Handle, STCFG_CMD_PIO_ENABLE, STCFG_PIO4_BIT4_IRB_NOT_IRDA); // PIO4_4 를 ASC2 TX 에 연결 if (ST_ErrorCode != ST_NO_ERROR) { STTBX_Print(("STCFG_Call(STCFG_PIO4_BIT4_IRB_NOT_IRDA)=%s\n", GetErrorText(ST_ErrorCode) )); return( ST_ErrorCode ); }
특히나 STCFG 를 볼 때는 반드시 application data sheet 를 같이 보기를 권한다.