Part Number: OMAPL138B-EP
Other Parts Discussed in Thread: OMAP-L138
Tool/software: Code Composer Studio
Hi
I am using NDK running on the ARM9 core of an OMAP-L138 to send measurement results via UDP broadcast packets once every second or so (see the source code below). The measurement data is coming from the C6000 DSP and is copied to the shared RAM. (Don't worry about that too much, it's working fine.)
This used to work fine for several days until I needed to change the program and add 2 more measurement values to the UDP packet. Now the new program gets stuck after some hours. I do not get an error code or debug message what so ever. But when I pause the ARM program using the debugger in CCS it seems to be stuck in an internal function called "emacEnqueueTx".
I already worked my way through the NDK troubleshooting guide given in the user guide and did some experiments. However as it takes several hours for this error to occur, I don't see a chance to attack this problem using the trial-and-error method.
I also made the kind of strange observation that the function udpBroadcastTaskFxn() associated with the task udpBroadcastTask is only called once after creation. Is this the desired behavior? However I worked around this issue by using a while(true) inside the task function and simply never returning from it. I don't know if this is relevant...
So here comes the code. It is essentially taken from the UDP hello world example code. I think the most interesting part starts at line 360:
/*
* Multi Frequency Analyzer
* Friedrich Feichtinger, 2019
*
* This is the part that runs on the ARM9
*
* Check for measurement results and send them over Ethernet
*/
#include "main.h"
// this is the data section shared between ARM and DSP
#pragma SET_DATA_SECTION(".sharedData")
SHARED_DATA sharedData;
#pragma SET_DATA_SECTION()
#define BUFSIZE 2048
char buf[BUFSIZE];
// Our NETCTRL callback functions
static void NetworkOpen();
static void NetworkClose();
static void NetworkIPAddr(uint32_t IPAddr, uint32_t IfIdx, uint32_t fAdd);
// Fun reporting function
static void ServiceReport(uint32_t Item, uint32_t Status, uint32_t Report, void* hCfgEntry);
// Tasks handles
void* udpBroadcastTask=NULL;
// Task functions
void udpBroadcastTaskFxn();
//---------------------------------------------------------------------
// Main Entry Point
//---------------------------------------------------------------------
int main()
{
// invalidate shared data
sharedData.currDataValid=false;
sharedData.meanDataValid=false;
//
// NOTE: The DSP program must be started first in order to enable RESETOUT before EMAC can be initialized
//
System_printf("waiting for the DSP to wake up...\n");
CSL_SysCfgUnlockKicker();
// set DSP boot address vector to entry point of DSP program
// this must be aligned to 1KB boundaries
sys0Regs->HOST1CFG = 0xc0000000;
// wake up the DSP
CSL_FINST(psc0Regs->MDCTL[CSL_PSC_DSP], PSC_MDCTL_NEXT, ENABLE);
CSL_FINST(psc0Regs->PTCMD, PSC_PTCMD_GO1, SET);
while(CSL_FEXT(psc0Regs->PTSTAT, PSC_PTSTAT_GOSTAT1)==CSL_PSC_PTSTAT_GOSTAT1_IN_TRANSITION);
CSL_FINST(psc0Regs->MDCTL[CSL_PSC_DSP], PSC_MDCTL_LRST, DEASSERT);
// wait for the DSP to wake up and load configuration
while(!sharedData.currDataValid)
{
Cache_inv((void*)&sharedData, sizeof(sharedData), Cache_Type_L1D, true); // invalidate cache before reading dataValid
}
//
// configure PSC and PINMUX for EMAC
//
CSL_SysCfgUnlockKicker();
// set NEXT state to ENABLE
CSL_PSC_setModuleNextState(CSL_PSC_EMAC, PSC_MODSTATE_ENABLE);
// set GO bit to initiate state transition
CSL_PSC_startStateTransition2(0);
// wait for power state transition to finish
while (!CSL_PSC_isStateTransitionDone2(0));
// wait for state transition
while (CSL_PSC_getModuleState(CSL_PSC_EMAC) != PSC_MODSTATE_ENABLE);
// enable the pinmux registers for RMII
hSysCfg->PINMUX14 &= ~0xFFFFFF00;
hSysCfg->PINMUX14 |= 0x88888800;
hSysCfg->PINMUX15 &= ~0x000000FF;
hSysCfg->PINMUX15 |= 0x00000080; // RMII_MHZ_50_CLK form external source
// enable the pinmux registers for MDIO
hSysCfg->PINMUX4 &= ~0x000000FF;
hSysCfg->PINMUX4 |= 0x00000088;
// select RMII mode
hSysCfg->CFGCHIP3 |= 0x00000100;
CSL_SysCfgLockKicker();
// set EMAC driver to RMII
EMAC_HwAttrs_V0 emac_cfg;
EMAC_socGetInitCfg(0, &emac_cfg);
emac_cfg.macSel = RMII;
EMAC_socSetInitCfg(0, &emac_cfg);
BIOS_start();
return 0;
}
//
// Main Thread
//
int init()
{
//
// THIS MUST BE THE ABSOLUTE FIRST THING DONE IN AN APPLICATION before using the stack!!
//
int rc;
rc = NC_SystemOpen( NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT );
if(rc!=0)
{
System_printf("NC_SystemOpen() failed (%d)\n", rc);
return -1;
}
//
// Create and build the system configuration from scratch.
//
// Create a new configuration
void* hCfg = CfgNew();
if(hCfg==NULL)
{
System_printf("Unable to create configuration\n");
NC_SystemClose();
return -1;
}
// We better validate the length of the supplied names
if(strlen(sharedData.networkConfig.domainName) >= CFG_DOMAIN_MAX || strlen(sharedData.networkConfig.hostName) >= CFG_HOSTNAME_MAX)
{
System_printf("Names too long\n");
NC_SystemClose();
return -1;
}
// Add our global hostname to hCfg (to be claimed in all connected domains)
rc = CfgAddEntry(hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_HOSTNAME, 0, strlen(sharedData.networkConfig.hostName), (uint8_t *)sharedData.networkConfig.hostName, 0);
if(rc<0)
{
System_printf("CfgAddEntry() failed: %d\n", rc);
NC_SystemClose();
return -1;
}
if(strcmp(sharedData.networkConfig.localIPAddr, "0.0.0.0")==0)
{
// wait 5s before trying to connect using DHCP
TaskSleep(5000);
// configure DHCP
CI_SERVICE_DHCPC dhcpc;
// Specify DHCP Service on IF-1
bzero(&dhcpc, sizeof(dhcpc));
dhcpc.cisargs.Mode = CIS_FLG_IFIDXVALID;
dhcpc.cisargs.IfIdx = 1;
dhcpc.cisargs.pCbSrv = &ServiceReport;
CfgAddEntry(hCfg, CFGTAG_SERVICE, CFGITEM_SERVICE_DHCPCLIENT, 0, sizeof(dhcpc), (uint8_t *)&dhcpc, 0);
}
else
{
// configure static IP
CI_IPNET NA;
CI_ROUTE RT;
uint32_t IPTmp;
// Setup manual IP address
bzero( &NA, sizeof(NA) );
NA.IPAddr = inet_addr(sharedData.networkConfig.localIPAddr);
NA.IPMask = inet_addr(sharedData.networkConfig.localIPMask);
strcpy( NA.Domain, sharedData.networkConfig.domainName);
NA.NetType = 0;
// Add the address to interface 1
CfgAddEntry( hCfg, CFGTAG_IPNET, 1, 0,
sizeof(CI_IPNET), (uint8_t *)&NA, 0 );
// Add the default gateway. Since it is the default, the
// destination address and mask are both zero (we go ahead
// and show the assignment for clarity).
bzero( &RT, sizeof(RT) );
RT.IPDestAddr = 0;
RT.IPDestMask = 0;
RT.IPGateAddr = inet_addr(sharedData.networkConfig.gatewayIP);
// Add the route
CfgAddEntry( hCfg, CFGTAG_ROUTE, 0, 0,
sizeof(CI_ROUTE), (uint8_t *)&RT, 0 );
// Manually add the DNS server when specified
IPTmp = inet_addr(sharedData.networkConfig.dnsServer);
if( IPTmp )
CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,
0, sizeof(IPTmp), (uint8_t *)&IPTmp, 0 );
}
//
// Configure IPStack/OS Options
//
// We don't want to see debug messages less than WARNINGS
int debugLevel = DBG_WARN;
CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_DBGPRINTLEVEL, CFG_ADDMODE_UNIQUE, sizeof(debugLevel), (uint8_t *)&debugLevel, 0);
//
// This code sets up the TCP and UDP buffer sizes
// (Note 8192 is actually the default. This code is here to
// illustrate how the buffer and limit sizes are configured.)
//
// UDP Receive limit
int bufSize = 8192;
CfgAddEntry(hCfg, CFGTAG_IP, CFGITEM_IP_SOCKUDPRXLIMIT, CFG_ADDMODE_UNIQUE, sizeof(bufSize), (uint8_t *)&bufSize, 0);
//
// Boot the system using this configuration
//
// We keep booting until the function returns 0. This allows
// us to have a "reboot" command.
//
do
{
rc = NC_NetStart( hCfg, NetworkOpen, NetworkClose, NetworkIPAddr );
} while(rc > 0);
// Delete Configuration
CfgFree(hCfg);
// Close the OS
NC_SystemClose();
return(0);
}
//
// NetworkOpen
//
// This function is called after the configuration has booted
//
static void NetworkOpen()
{
//System_printf("create task\n");
udpBroadcastTask = TaskCreate(udpBroadcastTaskFxn, "udpBroadcastTask", OS_TASKPRINORM, OS_TASKSTKHIGH, 0, 0, 0);
if(udpBroadcastTask==NULL)
{
System_printf("TaskCreate() failed!\n");
}
}
//
// NetworkClose
//
// This function is called when the network is shutting down,
// or when it no longer has any IP addresses assigned to it.
//
static void NetworkClose()
{
TaskDestroy(udpBroadcastTask);
System_printf("task destroyed!\n");
}
//
// NetworkIPAddr
//
// This function is called whenever an IP address binding is
// added or removed from the system.
//
static void NetworkIPAddr( uint32_t IPAddr, uint32_t IfIdx, uint32_t fAdd )
{
uint32_t IPTmp;
if(fAdd)
{
System_printf("Network Added: ");
}
else
{
System_printf("Network Removed: ");
}
// Print a message
IPTmp = NDK_ntohl( IPAddr );
System_printf("If-%d:%d.%d.%d.%d\n", IfIdx,
(uint8_t)(IPTmp>>24)&0xFF, (uint8_t)(IPTmp>>16)&0xFF,
(uint8_t)(IPTmp>>8)&0xFF, (uint8_t)IPTmp&0xFF );
}
//
// Service Status Reports
//
// Here's a quick example of using service status updates
//
static char *TaskName[] = { "Telnet","HTTP","NAT","DHCPS","DHCPC","DNS" };
static char *ReportStr[] = { "","Running","Updated","Complete","Fault" };
static char *StatusStr[] = { "Disabled","Waiting","IPTerm","Failed","Enabled" };
static void ServiceReport( uint32_t Item, uint32_t Status, uint32_t Report, void* h )
{
System_printf("Service Status: %-9s: %-9s: %-9s: %03d\n",
TaskName[Item-1], StatusStr[Status],
ReportStr[Report/256], Report&0xFF );
//
// Example of adding to the DHCP configuration space
//
// When using the DHCP client, the client has full control over access
// to the first 256 entries in the CFGTAG_SYSINFO space.
//
// Note that the DHCP client will erase all CFGTAG_SYSINFO tags except
// CFGITEM_DHCP_HOSTNAME. If the application needs to keep manual
// entries in the DHCP tag range, then the code to maintain them should
// be placed here.
//
// Here, we want to manually add a DNS server to the configuration, but
// we can only do it once DHCP has finished its programming.
//
if( Item == CFGITEM_SERVICE_DHCPCLIENT &&
Status == CIS_SRV_STATUS_ENABLED &&
(Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPADD) ||
Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPRENEW)) )
{
uint32_t IPTmp;
// Manually add the DNS server when specified
IPTmp = inet_addr(sharedData.networkConfig.dnsServer);
if( IPTmp )
CfgAddEntry( 0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER,
0, sizeof(IPTmp), (uint8_t *)&IPTmp, 0 );
}
}
//
// UDP Broadcast Function
//
void udpBroadcastTaskFxn()
{
System_printf("udpBroadcast...\n");
//TaskSleep(5000);
while(true)
{
System_flush();
// create a UDP socket
SOCKET s = NDK_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(s==INVALID_SOCKET)
{
System_printf("NDK_socket() failed, error code: %d\n", fdError());
return;
}
// enable broadcast on socket
int broadcast = 1;
if(NDK_setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast))==-1)
{
System_printf("NDK_setsockopt() failed, error code: %d\n", fdError());
fdClose(s);
return;
}
// configure port and destination address (broadcast)
struct sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = NDK_htons(sharedData.networkConfig.resultPortNr);
if(strcmp(sharedData.networkConfig.destIP, "255.255.255.255"))
{
addr.sin_addr.s_addr = NDK_htonl(INADDR_BROADCAST);
}
else
{
addr.sin_addr.s_addr = inet_addr(sharedData.networkConfig.destIP);
}
// buffer for UDP message
//#define BUFSIZE 2048
//char buf[BUFSIZE];
//char buf[] = "hello there\n";
/*
char string[] = "{}\n";
NDK_sendto(s, string, strlen(string), 0, (struct sockaddr*)&addr, sizeof(addr));
*/
// read measurement result from shared RAM and send UDP broadcast
Cache_inv((void*)&sharedData, sizeof(sharedData), Cache_Type_L1D, true); // invalidate cache before reading data
if(sharedData.currDataValid)
{
// send message
snprintf(buf, BUFSIZE, "{\"systemState\":\"0x%04x\", \"frameNr\":%d, \"rbeCode\":%d, "
"\"fr\":%.3f, \"Q\":%.3f, \"phi0\":%.3f, \"D\":%g, "
"\"T\":%.3f, \"rho\":%.3f, \"eta\":%.6f, \"TAdc\":%.1f, \"TBack\":%.1f, "
"\"AIn0\":%.3f, \"AIn1\":%.3f, \"uPel\":%.3f, \"iPel\":%.3f}\n",
sharedData.systemState, sharedData.frameNr, sharedData.rbeCode,
sharedData.fr, sharedData.Q, sharedData.phi0, sharedData.D,
sharedData.T, sharedData.rho, sharedData.eta, sharedData.TAdc, sharedData.TBack,
sharedData.AInVoltage[0], sharedData.AInVoltage[1], sharedData.uPel, sharedData.iPel);
sharedData.currDataValid=false;
Cache_wb((void*)&sharedData, sizeof(sharedData), Cache_Type_L1D, true); // write back cache to shared RAM
int ret=NDK_sendto(s, buf, strlen(buf), 0, (struct sockaddr*)&addr, sizeof(addr));
if(ret<200 || ret>300)
{
System_printf("NDK_sendto() ret code: %d\n", ret);
}
if(ret==-1)
{
System_printf("NDK_sendto() failed, error code: %d\n", fdError());
fdClose(s);
return;
}
}
if(sharedData.meanDataValid)
{
// send message
snprintf(buf, BUFSIZE, "{\"TMean\":%.3f, \"rhoMean\":%.3f, \"etaMean\":%.6f}\n",
sharedData.TMean, sharedData.rhoMean, sharedData.etaMean);
sharedData.meanDataValid=false;
Cache_wb((void*)&sharedData, sizeof(sharedData), Cache_Type_L1D, true); // write back cache to shared RAM
int ret=NDK_sendto(s, buf, strlen(buf), 0, (struct sockaddr*)&addr, sizeof(addr));
//System_printf("NDK_sendto() ret code: %d\n", ret);
if(ret==-1)
{
System_printf("NDK_sendto() failed, error code: %d\n", fdError());
fdClose(s);
return;
}
}
if(NDK_shutdown(s, SHUT_RDWR)==-1)
{
System_printf("NDK_shutdown() failed, error code: %d\n", fdError());
fdClose(s);
return;
}
if(fdClose(s)==-1)
{
System_printf("fdClose() failed, error code: %d\n", fdError());
return;
}
// sleep for 100 msec
TaskSleep(100);
}
}
Thanks a lot for any hint!
Kind Regards, Fritz