Dear community/employees
I am trying to implement LwiP stack on LCDK6748 using StarterWare 1_20_03_03 library. Unfortunately provided examples are ported for Cortex-A8 :am335x , am1808 , c6x811x only so I decided to write my own low-level hardware initialization. I followed steps pointed in http://processors.wiki.ti.com/index.php/StarterWare_EMAC and here is my code :
void main()
{
PSCModuleControl(SOC_PSC_1_REGS,HW_PSC_GPIO, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
EMACPinMuxSetup();
PSCModuleControl(SOC_PSC_1_REGS,HW_PSC_EMAC, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
GPIOBank6Pin12PinMuxSetup();
GPIOBank6Pin13PinMuxSetup();
GPIOBank2Pin12PinMuxSetup();
GPIOBank0Pin9PinMuxSetup();
GPIOBank2Pin4PinMuxSetup();
GPIODirModeSet(SOC_GPIO_0_REGS, 109, GPIO_DIR_OUTPUT);
GPIODirModeSet(SOC_GPIO_0_REGS, 110, GPIO_DIR_OUTPUT);
GPIODirModeSet(SOC_GPIO_0_REGS, 45, GPIO_DIR_OUTPUT);
GPIODirModeSet(SOC_GPIO_0_REGS, 10, GPIO_DIR_OUTPUT);
GPIODirModeSet(SOC_GPIO_0_REGS, 37, GPIO_DIR_INPUT);
/* Configuration of Timer */
TimerConfigure(SOC_TMR_2_REGS, TMR_CFG_64BIT_CLK_INT);
/* Set the 64 bit timer period */
TimerPeriodSet(SOC_TMR_2_REGS, TMR_TIMER12, 0x000249F0);
TimerPeriodSet(SOC_TMR_2_REGS, TMR_TIMER34, 0);
InterruptSetup();
TimerIntEnable(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
TimerEnable(SOC_TMR_2_REGS, TMR_TIMER12, TMR_ENABLE_CONT);
LwIP_Init();
while(1)
{
if(GPIOPinRead(SOC_GPIO_0_REGS,37))
GPIOPinWrite(SOC_GPIO_0_REGS, 10, GPIO_PIN_LOW);
else
GPIOPinWrite(SOC_GPIO_0_REGS, 10, GPIO_PIN_HIGH);
sys_check_timeouts();
}
}
void LwIP_Init()
{
//phy addr = 0x7;
ip_addr_t addr, netmask, gw;
IP4_ADDR(&addr, 192, 168, 10, 139);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gw, 192, 168, 10, 1);
netif_add(&netif, &addr, &netmask, &gw, 0, emac_init, ethernet_input);
netif_set_default(&netif);
netif_set_up(&netif);
lwip_init();
}
err_t emac_init(struct netif *netif)
{
uint32_t i;
uint16_t partnerAbility=0;
/* LwIP network interface level */
netif->name[0] = 'e';
netif->name[1] = 't';
netif->output = etharp_output;
netif->linkoutput = emac_low_level_output;
//netif->igmp_mac_filter = c674emac_igmp_mac_filter;
netif->hwaddr[0] = MAC_Addr[0];
netif->hwaddr[1] = MAC_Addr[1];
netif->hwaddr[2] = MAC_Addr[2];
netif->hwaddr[3] = MAC_Addr[3];
netif->hwaddr[4] = MAC_Addr[4];
netif-> hwaddr[5] = MAC_Addr[5];
#if LWIP_NETIF_HOSTNAME
netif->hostname = "lwip";
#endif
netif->hwaddr_len = ETHARP_HWADDR_LEN;
netif->mtu = 1500;
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP/*| NETIF_FLAG_IGMP*/;
EMACInit(SOC_EMAC_DSC_CTRL_MOD_REG,SOC_EMAC_DSC_CONTROL_REG);
MDIOInit(SOC_MDIO_0_REGS,phySysClk/2000,phySysClk/10);
for(i=0;i<5000;i++);//short delay
if(Lan8710aAutoNegotiate(SOC_MDIO_0_REGS,0x07,LAN8710A_100BTX_FD | LAN8710A_100BTX | LAN8710A_10BT_FD | LAN8710A_10BT) == FALSE)
return ERR_IF;
if(Lan8710aPartnerAbilityGet(SOC_MDIO_0_REGS,0x07,&partnerAbility) == FALSE)
return ERR_IF;
EMACDuplexSet(SOC_EMAC_DSC_CONTROL_REG,EMAC_DUPLEX_FULL);
EMACMACAddrSet(SOC_EMAC_DSC_CONTROL_REG,0,MAC_Addr,EMAC_MACADDR_NO_MATCH_NO_FILTER);
EMACRxUnicastSet(SOC_EMAC_DSC_CONTROL_REG,0);
initDescriptors();
//uint32_t linkStatus = MDIOPhyLinkStatusGet(SOC_MDIO_0_REGS);
EMACTxEnable(SOC_EMAC_DSC_CONTROL_REG);
EMACRxEnable(SOC_EMAC_DSC_CONTROL_REG);
EMACRxHdrDescPtrWrite(SOC_EMAC_DSC_CONTROL_REG,EMAC_RXHDP(0),0);
EMACMIIEnable(SOC_EMAC_DSC_CONTROL_REG);
EMACTxIntPulseEnable(SOC_EMAC_DSC_CONTROL_REG,SOC_EMAC_DSC_CTRL_MOD_REG,0,0);
EMACRxIntPulseEnable(SOC_EMAC_DSC_CONTROL_REG,SOC_EMAC_DSC_CTRL_MOD_REG,0,0);
return ERR_OK;
}
void initDescriptors(void)
{
/* Prepare Descriptors */
struct cppiram_t* cppiram = (struct cppiram_t*) SOC_EMAC_DSC_CTRL_MOD_RAM;
memset(cppiram, 0, sizeof(struct cppiram_t));
uint16_t i;
for (i=0; i<TX_DESCRIPTORS; i++)
{
push_desc(&cppiram->txfree, &cppiram->txdesc[i]);
}
for (i=0; i<RX_DESCRIPTORS; i++)
{
struct pbuf* p = pbuf_alloc(PBUF_RAW, 1520, PBUF_POOL);
cppiram->rxdesc[i].pBuffer = (Uint8*) p;
cppiram->rxdesc[i].BufOffLen = 1536;
cppiram->rxdesc[i].PktFlgLen = EMAC_DSC_FLAG_OWNER | 0;
//L2CACHE_WBINV(p, 1536);
push_desc(&cppiram->rxactive, &cppiram->rxdesc[i]);
}
}
void push_desc(struct dma_queue_t* q, struct EMAC_Desc* desc)
{
desc->next = 0;
if (q->first)
q->last->next = desc;
else
q->first = desc;
q->last = desc;
q->n++;
}
return ERR_OK;
}
/*
** Timer Interrupt Service Routine
*/
static void TimerIsr(void)
{
/* Disable the timer interrupt */
TimerIntDisable(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
IntEventClear(SYS_INT_T64P2_TINTALL);
TimerIntStatusClear(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
totalMiliseconds++;
/* Enable the timer interrupt */
TimerIntEnable(SOC_TMR_2_REGS, TMR_INT_TMR12_NON_CAPT_MODE);
}
u32_t sys_now(void)
{
return totalMiliseconds;
}
void InterruptSetup(void)
{
// Initialize the DSP Interrupt Controller
IntDSPINTCInit();
/* Register the Timer ISR */
IntRegister(C674X_MASK_INT6, TimerIsr);
/* Map Timer interrupts to DSP maskable interrupt */
IntEventMap(C674X_MASK_INT6, SYS_INT_T64P2_TINTALL);
/* Enable DSP interrupt in DSPINTC */
IntEnable(C674X_MASK_INT6);
// Enable DSP Interrupts Globally
IntGlobalEnable();
// Register the ISR in the Interrupt Vector Table
IntRegister(C674X_MASK_INT4, EMACCore0RxIsr);
IntRegister(C674X_MASK_INT5, EMACCore0TxIsr);
// Map the system interrupt to the DSP maskable interrupt
IntEventMap(C674X_MASK_INT4, SYS_INT_EMAC_C0RX);
IntEventMap(C674X_MASK_INT5, SYS_INT_EMAC_C0TX);
// Enable DSP maskable interrupt
IntEnable(C674X_MASK_INT4);
IntEnable(C674X_MASK_INT5);
}
void EMACCore0RxIsr(void)
{
IntEventClear(SYS_INT_EMAC_C0RX);
}
void EMACCore0TxIsr(void)
{
IntEventClear(SYS_INT_EMAC_C0TX);
}
My problem is that EMAC core interrupts aren't called after EMAC initilalization so I cannot process any incoming Ethernet packets and pass them to upper-layer Lwip function calls. Simply program counter doesn't show in either EMACCore0TxIsr or EMACCore0RxIsr. However, timer interrput and GPIOs are working well. Could anyone tell me how to write low-level driver for C6748 EMAC ? The only ports I found are for SYS/BIOS and I need bare-matal TCP/IP stack solution.