I tried to implement a TFTP protocol in the EK-TM4C1294NCPDT board, using the files tftp.c and tftp.h contained in the utils folder on TivaWare 2.1.3.156. I want to read the value of specific memory position in the flash via TFTP.
As there are not examples of this protocol for my board, I use the enet_io example and I modifying for add a TFTP protocol implementation. I initialize the TFTP using TFTPInit function, as it is in the code below:
int
main(void)
{
uint32_t ui32User0, ui32User1;
uint8_t pui8MACArray[8];
//
// 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.
//
SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);
//
// Run from the PLL at 120 MHz.
//
g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480), 120000000);
//
// Configure the device pins.
//
PinoutSet(true, false);
//
// Configure debug port for internal use.
//
UARTStdioConfig(0, 115200, g_ui32SysClock);
//
// Clear the terminal and print a banner.
//
UARTprintf("\033[2J\033[H");
UARTprintf("Ethernet IO Example\n\n");
//
// Configure SysTick for a periodic interrupt.
//
MAP_SysTickPeriodSet(g_ui32SysClock / SYSTICKHZ);
MAP_SysTickEnable();
MAP_SysTickIntEnable();
//
// Configure the hardware MAC address for Ethernet Controller filtering of
// incoming packets. The MAC address will be stored in the non-volatile
// USER0 and USER1 registers.
//
MAP_FlashUserGet(&ui32User0, &ui32User1);
if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff))
{
//
// Let the user know there is no MAC address
//
UARTprintf("No MAC programmed!\n");
while(1)
{
}
}
//
// Tell the user what we are doing just now.
//
UARTprintf("Waiting for IP.\n");
//
// 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.
//
pui8MACArray[0] = ((ui32User0 >> 0) & 0xff);
pui8MACArray[1] = ((ui32User0 >> 8) & 0xff);
pui8MACArray[2] = ((ui32User0 >> 16) & 0xff);
pui8MACArray[3] = ((ui32User1 >> 0) & 0xff);
pui8MACArray[4] = ((ui32User1 >> 8) & 0xff);
pui8MACArray[5] = ((ui32User1 >> 16) & 0xff);
//
// Initialze the lwIP library, using DHCP.
//
lwIPInit(g_ui32SysClock, pui8MACArray, 0, 0, 0, IPADDR_USE_DHCP);
// lwIPInit(g_ui32SysClock, pui8MACArray, 2887557220, 4294934528, 2887526654, IPADDR_USE_STATIC);
//
// Setup the device locator service.
//
LocatorInit();
LocatorMACAddrSet(pui8MACArray);
LocatorAppTitleSet("EK-TM4C1294XL enet_io");
uint32_t i;
for(i = 0; i < 99; i++) {
buffer[i] = 'a';
}
buffer[99] = '\0';
//
// Initialize a sample httpd server.
//
httpd_init();
TFTPInit(okToContinue);
//
// Set the interrupt priorities. We set the SysTick interrupt to a higher
// priority than the Ethernet interrupt to ensure that the file system
// tick is processed if SysTick occurs while the Ethernet handler is being
// processed. This is very likely since all the TCP/IP and HTTP work is
// done in the context of the Ethernet interrupt.
//
MAP_IntPrioritySet(INT_EMAC0, ETHERNET_INT_PRIORITY);
MAP_IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY);
//
// Pass our tag information to the HTTP server.
//
http_set_ssi_handler((tSSIHandler)SSIHandler, g_pcConfigSSITags,
NUM_CONFIG_SSI_TAGS);
//
// Pass our CGI handlers to the HTTP server.
//
http_set_cgi_handlers(g_psConfigCGIURIs, NUM_CONFIG_CGI_URIS);
//
// Initialize IO controls
//
io_init();
//
// Loop forever, processing the on-screen animation. All other work is
// done in the interrupt handlers.
//
while(1)
{
//
// Wait for a new tick to occur.
//
while(!g_ulFlags)
{
//
// Do nothing.
//
}
//
// Clear the flag now that we have seen it.
//
HWREGBITW(&g_ulFlags, FLAG_TICK) = 0;
//
// Toggle the GPIO
//
MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1,
(MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) ^
GPIO_PIN_1));
}
}
I created the callback functions, but now I implemented only the TFTPInit and pfnGetData Callback.
tTFTPError getDataFromTFTP(struct _tTFTPConnection *psTFTP){
unsigned long ulOffset;
UARTprintf("Get block %d, %d\n", psTFTP->ui32BlockNum, psTFTP->ui32DataLength);
//
// Where does this block of data get read from? This is calculated from
// the requested TFTP block number.
//
ulOffset = ((psTFTP->ui32BlockNum - 1) * TFTP_BLOCK_SIZE);
//
// Copy the data into the supplied buffer.
//
memcpy(psTFTP->pui8Data, (unsigned char *)(buffer + ulOffset),
psTFTP->ui32DataLength);
//
// Tell the caller everything went fine.
//
return(TFTP_OK);
}
tTFTPError putDataFromTFTP(struct _tTFTPConnection *psTFTP){
return TFTP_OK;
}
void closeTFTP(struct _tTFTPConnection *psTFTP){
}
tTFTPError okToContinue(struct _tTFTPConnection *psTFTP, bool bGet,
int8_t *pui8FileName, tTFTPMode eMode){
psTFTP->pfnClose = closeTFTP;
//
// Is this a GET or PUT request?
//
if(bGet)
{
//
// GET request - fill in the image size and the data transfer
// function pointer.
//
psTFTP->pfnGetData = getDataFromTFTP;
psTFTP->ui32DataRemaining = 100;
}
else
{
//
// PUT request - fill in the data transfer function pointer.
//
psTFTP->pfnPutData = putDataFromTFTP;
}
return TFTP_OK;
}
The board got the IP adress and the http server worked perfectly. But when I use a native TFTP client in the windows, the TFTPRecv function and the pfnGetData callback function is called. But the TFTPRecv function is called , when the TFTPDataRecv function should be called, and occurs the Fault_ISR when udp_recv in the line 618 is called again.
Why the function TFTPDataRecv is never called?