Other Parts Discussed in Thread: TM4C129ENCPDT, TM4C1294NCPDT
Hello All, I am wondering if someone has had any experience with the following issue. I am using a TM4C129ENCPDT, running with a 25Mhz external crystal oscillator. I am using TivaWare_C_Series-2.1.0.12573 and CCS 6.0.1.00040. The code is running on our own hardware, and I do not have a demo kit to try it out on.
I have been experiencing a controller lockup, where I can not connect to the board with JTAG after the error occurs. The following is the code I am running, a simple program that initializes the clock, ethernet, configures the ethernet PHY, toggles a port and then performs a soft reset. This code is mostly all borrowed from section 10.3 Programming Example, in the Tivaware Peripheral Driver Library User's Guide dated Feb 7, 2014.
If I leave this code running for a while(usually under an hour) it will lock up. I have already checked the NmiSR, FaultISR and Default ISR handler, and these are not the cause of the lockup, they are never fired. It also seems that the code locks up in different places, as I have tried instrumenting the code by toggling LEDs at different times, and I have had it lock up in different places. It seems it is most likely to occur around the call to EMACPHYConfigSet, but it appears to be a bit random.
If I remove the delay between the clock initialization and the rest of the program I no longer get the program to lock up. I am wondering what could be causing the lockup, and why removing the delay could fix it. A power cycle is needed to get the program to run after it locks up. Any help solving this will be greatly appreciated!
//*****************************************************************************
//
// Ethernet DMA descriptors.
//
// The MAC hardware needs a minimum of 3 receive descriptors to operate. The
// number used will be application-dependent and should be tuned for best
// performance.
//
//*****************************************************************************
#define NUM_TX_DESCRIPTORS 3
#define NUM_RX_DESCRIPTORS 3
tEMACDMADescriptor g_psRxDescriptor[NUM_TX_DESCRIPTORS];
tEMACDMADescriptor g_psTxDescriptor[NUM_RX_DESCRIPTORS];
uint32_t g_ui32RxDescIndex;
uint32_t g_ui32TxDescIndex;
//*****************************************************************************
//
// Transmit and receive buffers. These will typically be allocated within your
// network stack somewhere.
//
//*****************************************************************************
#define RX_BUFFER_SIZE 1536
uint8_t g_ppui8RxBuffer[NUM_RX_DESCRIPTORS][RX_BUFFER_SIZE];
//*****************************************************************************
//
// Read a packet from the DMA receive buffer and return the number of bytes
// read.
//
//*****************************************************************************
int32_t ProcessReceivedPacket(void)
{
int_fast32_t i32FrameLen;
//
// By default, we assume we got a bad frame.
//
i32FrameLen = 0;
//
// Make sure that we own the receive descriptor.
//
if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & DES0_RX_CTRL_OWN))
{
//
// We own the receive descriptor so check to see if it contains a valid
// frame.
//
if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
DES0_RX_STAT_ERR))
{
//
// We have a valid frame. First check that the "last descriptor"
// flag is set. We sized the receive buffer such that it can
// always hold a valid frame so this flag should never be clear at
// this point but...
//
if(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
DES0_RX_STAT_LAST_DESC)
{
//
// What size is the received frame?
//
i32FrameLen =
((g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus &
DES0_RX_STAT_FRAME_LENGTH_M) >>
DES0_RX_STAT_FRAME_LENGTH_S);
//
// Pass the received buffer up to the application to handle.
//
//ApplicationProcessFrame(i32FrameLen,
//g_psRxDescriptor[g_ui32RxDescIndex].pvBuffer1);
}
}
//
// Now that we are finished dealing with this descriptor, hand
// it back to the hardware. Note that we assume
// ApplicationProcessFrame() is finished with the buffer at this point
// so it is safe to reuse.
//
g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus =
DES0_RX_CTRL_OWN;
//
// Move on to the next descriptor in the chain.
//
g_ui32RxDescIndex++;
if(g_ui32RxDescIndex == NUM_RX_DESCRIPTORS)
{
g_ui32RxDescIndex = 0;
}
}
//
// Return the Frame Length
//
return(i32FrameLen);
}
//*****************************************************************************
//
// The interrupt handler for the Ethernet interrupt.
//
//*****************************************************************************
void EthernetIntHandler(void)
{
uint32_t ui32Temp;
//
// Read and Clear the interrupt.
//
ui32Temp = EMACIntStatus(EMAC0_BASE, true);
EMACIntClear(EMAC0_BASE, ui32Temp);
//
// Check to see if an RX Interrupt has occurred.
//
if(ui32Temp & EMAC_INT_RECEIVE)
{
//
// Indicate that a packet has been received.
//
ProcessReceivedPacket();
}
}
int main(void)
{
uint32_t ui32SysClock;
uint32_t ui32User0, ui32User1, ui32Loop;
uint8_t ui8PHYAddr;
uint8_t pui8MACAddr[6];
// Make sure the main oscillator is enabled because this is required by
// the PHY. The system must have a 25MHz crystal attached to the OSC
// pins. The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal
// frequency is 10MHz or higher.
HWREG(SYSCTL_MOSCCTL) = SYSCTL_MOSC_HIGHFREQ;
ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
//***********This delay BREAKS the program ********************************//
ROM_SysCtlDelay(5242880);
//*************************************************************************//
//
// Configure the device pins.
//
// PK4 is used for Ethernet LEDs.
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
ROM_GPIOPinConfigure(GPIO_PK4_EN0LED0);
//
// Make the pin(s) be peripheral controlled.
//
ROM_GPIODirModeSet(GPIO_PORTK_BASE, GPIO_PIN_4, GPIO_DIR_MODE_HW);
//
// Set the pad(s) for standard push-pull operation.
//
GPIOPadConfigSet(GPIO_PORTK_BASE, GPIO_PIN_4|GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
//
// Read the MAC address from the user registers.
// Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
// address needed to program the hardware registers, then program the MAC
// address into the Ethernet Controller registers.
//
pui8MACAddr[0] = 0x00;
pui8MACAddr[1] = 0x1a;
pui8MACAddr[2] = 0xb6;
pui8MACAddr[3] = 0x00;
pui8MACAddr[4] = 0x64;
pui8MACAddr[5] = 0x00;
//
// Enable and reset the Ethernet modules.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
//
// Wait for the MAC to be ready.
//
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
{
}
//
// Configure for use with the internal PHY.
//
EMACPHYConfigSet(EMAC0_BASE, (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | EMAC_PHY_AN_100B_T_FULL_DUPLEX));
//
// Reset the MAC to latch the PHY configuration.
//
EMACReset(EMAC0_BASE);
//
// Initialize the MAC and set the DMA mode.
//
EMACInit(EMAC0_BASE, ui32SysClock, EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0);
//
// Set MAC configuration options.
//
EMACConfigSet( EMAC0_BASE,
(EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD | EMAC_CONFIG_7BYTE_PREAMBLE |
EMAC_CONFIG_IF_GAP_96BITS | EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR |
EMAC_CONFIG_BO_LIMIT_1024),
(EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD | EMAC_MODE_TX_THRESHOLD_64_BYTES | EMAC_MODE_RX_THRESHOLD_64_BYTES),
0);
// Initialize each of the transmit descriptors. Note that we leave the
// buffer pointer and size empty and the OWN bit clear here since we have
// not set up any transmissions yet.
//
for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++)
{
g_psTxDescriptor[ui32Loop].ui32Count = DES1_TX_CTRL_SADDR_INSERT;
g_psTxDescriptor[ui32Loop].DES3.pLink =
(ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ?
g_psTxDescriptor : &g_psTxDescriptor[ui32Loop + 1];
g_psTxDescriptor[ui32Loop].ui32CtrlStatus =
(DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG |
DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED |
DES0_TX_CTRL_IP_ALL_CKHSUMS);
}
// Initialize each of the receive descriptors. We clear the OWN bit here
// to make sure that the receiver doesn’t start writing anything
// immediately.
//
for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++)
{
g_psRxDescriptor[ui32Loop].ui32CtrlStatus = 0;
g_psRxDescriptor[ui32Loop].ui32Count =
(DES1_RX_CTRL_CHAINED |
(RX_BUFFER_SIZE << DES1_RX_CTRL_BUFF1_SIZE_S));
g_psRxDescriptor[ui32Loop].pvBuffer1 = g_ppui8RxBuffer[ui32Loop];
g_psRxDescriptor[ui32Loop].DES3.pLink =
(ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ?
g_psRxDescriptor : &g_psRxDescriptor[ui32Loop + 1];
}
//
// Set the descriptor pointers in the hardware.
//
ROM_EMACRxDMADescriptorListSet(EMAC0_BASE, g_psRxDescriptor);
ROM_EMACTxDMADescriptorListSet(EMAC0_BASE, g_psTxDescriptor);
//
// Start from the beginning of both descriptor chains. We actually set
// the transmit descriptor index to the last descriptor in the chain
// since it will be incremented before use and this means the first
// transmission we perform will use the correct descriptor.
//
g_ui32RxDescIndex = 0;
g_ui32TxDescIndex = NUM_TX_DESCRIPTORS - 1;
//
// Program the hardware with its MAC address (for filtering).
//
EMACAddrSet(EMAC0_BASE, 0, pui8MACAddr);
//
// Wait for the link to become active.
//
while(( EMACPHYRead(EMAC0_BASE, 0, EPHY_BMSR) &
EPHY_BMSR_LINKSTAT) == 0)
{
}
//
// Set MAC filtering options. We receive all broadcast and multicast
// packets along with those addressed specifically for us.
//
EMACFrameFilterSet(EMAC0_BASE, (EMAC_FRMFILTER_SADDR | EMAC_FRMFILTER_PASS_MULTICAST | EMAC_FRMFILTER_PASS_NO_CTRL));
//
// Clear any pending interrupts.
//
EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false));
//
// Mark the receive descriptors as available to the DMA to start
// the receive processing.
//
for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++)
{
g_psRxDescriptor[ui32Loop].ui32CtrlStatus |= DES0_RX_CTRL_OWN;
}
//
// Enable the Ethernet MAC transmitter and receiver.
//
EMACTxEnable(EMAC0_BASE);
EMACRxEnable(EMAC0_BASE);
//
// Enable the Ethernet interrupt.
//
IntEnable(INT_EMAC0);
//
// Enable the Ethernet RX Packet interrupt source.
//
EMACIntEnable(EMAC0_BASE, EMAC_INT_RECEIVE);
//
// Application main loop continues....
//
GPIOInit('K', 6, GPIO_OUTPUT);
GPIOSet('K', 6, GPIO_ON);//Toggle LED On
ROM_SysCtlDelay(30000000);
GPIOSet('K', 6, GPIO_OFF);//Toggle LED Off
ROM_SysCtlReset();
while(1)
{
//
// Cannot reach this point in code.
//
}
}