UART sending data from embedded program


#1

Hi guys,

I’ve found the forum really useful as I don’t have any experience using UARTs and the FCM is very confusing for me. The following code runs fine in ‘Debug’ mode on the Q2406B:

#include "adl_global.h"

/***************************************************************************/
/*  Mandatory variables                                                    */
/*-------------------------------------------------------------------------*/
/*  wm_apmCustomStack                                                      */
/*  wm_apmCustomStackSize                                                  */
/*-------------------------------------------------------------------------*/
/***************************************************************************/
u32 wm_apmCustomStack [ 256 ];
const u16 wm_apmCustomStackSize = sizeof ( wm_apmCustomStack );

/***************************************************************************/
/*  Local variables                                                        */
/***************************************************************************/
s8 UART1_Handle;
ascii msg_test[20];
u16 msg_length;

/***************************************************************************/
/*  Local functions                                                        */
/***************************************************************************/
bool hnd_fcmData_U1 ( u16 DataSize, u8 * Data );
bool hnd_fcmCtrl_U1 ( adl_fcmEvent_e Event );
void UART1_Enable(void);
void hnd_tmrMessage_U1 ( u8 ID );

bool hnd_fcmData_U1 ( u16 DataSize, u8 * Data )
{
	adl_atSendResponse ( ADL_AT_UNS, "\r\n>> hnd_fcmData_U1\r\n");
	
	return TRUE;
}

bool hnd_fcmCtrl_U1 ( adl_fcmEvent_e Event )
{
	adl_atSendResponse ( ADL_AT_UNS, "\r\n>> hnd_fcmCtrl_U1:");

	switch (Event)
	{
		case ADL_FCM_EVENT_FLOW_OPENNED :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_FLOW_OPENNED\r\n");
			adl_fcmSwitchV24State(UART1_Handle, ADL_FCM_V24_STATE_DATA); 
		break;
		case ADL_FCM_EVENT_FLOW_CLOSED :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_FLOW_CLOSED\r\n");
		break;
		case ADL_FCM_EVENT_V24_DATA_MODE :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_DATA_MODE\r\n");
			adl_tmrSubscribe ( TRUE, 10, ADL_TMR_TYPE_100MS, hnd_tmrMessage_U1 );
		break;
		case ADL_FCM_EVENT_V24_DATA_MODE_EXT :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_DATA_MODE_EXT\r\n");
		break;
		case ADL_FCM_EVENT_V24_AT_MODE :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_AT_MODE\r\n");
			adl_fcmSendData(UART1_Handle, "AT Mode\r\n", 9);
		break;
		case ADL_FCM_EVENT_V24_AT_MODE_EXT :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_AT_MODE_EXT\r\n");
		break;
		case ADL_FCM_EVENT_RESUME :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_RESUME\r\n");
		break;
		case ADL_FCM_EVENT_MEM_RELEASE :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_MEM_RELEASE\r\n");
		break;
		case ADL_FCM_EVENT_V24_DATA_MODE_FROM_CALL :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_DATA_MODE_FROM_CALL\r\n");
		break;
		case ADL_FCM_EVENT_V24_AT_MODE_FROM_CALL :
			adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_AT_MODE_FROM_CALL\r\n");
		break;
	}
	return TRUE;
}

void UART1_Enable(void)
{
	adl_atSendResponse ( ADL_AT_UNS, "\r\n>> UART1_Enable\r\n");

	UART1_Handle = adl_fcmSubscribe ( ADL_FCM_FLOW_V24_UART1, hnd_fcmCtrl_U1, hnd_fcmData_U1);
}

void hnd_tmrMessage_U1 ( u8 ID )
{
	wm_sprintf(msg_test, "\r\nTest Message on UART 1\r\n");
	msg_length = wm_strlen(msg_test);

	adl_fcmSendData(UART1_Handle, msg_test, msg_length);

    adl_atSendResponse ( ADL_AT_UNS, "\r\n>> hnd_tmrMessage_U1 \r\n" );
}

/***************************************************************************/
/*  Function   : adl_main                                                  */
/*-------------------------------------------------------------------------*/
/*  Object     : Customer application initialisation                       */
/*                                                                         */
/*-------------------------------------------------------------------------*/
/*  Variable Name     |IN |OUT|GLB|  Utilisation                           */
/*--------------------+---+---+---+----------------------------------------*/
/*  InitType          |   |   |   |  Application start mode reason         */
/*--------------------+---+---+---+----------------------------------------*/
/***************************************************************************/
void adl_main ( adl_InitType_e InitType )
{
	adl_atSendResponse ( ADL_AT_UNS, "\r\n>> Start Rev1.0.1 \r\n" );

    // TO DO : Add your initialization code here
	UART1_Enable();
}

However, when I compile the Wimo Target mode and program the *.dwl onto the Q2406B, it outputs the following:

>> hnd_fcmCtrl_U1: ADL_FCM_EVENT_FLOW_OPENNED

The program then hangs and eventually the modem resets itself. It seems that the line

adl_fcmSwitchV24State(UART1_Handle, ADL_FCM_V24_STATE_DATA);

is not executing correctly, as the ADL_FCM_EVENT_V24_DATA_MODE state is never reached. Does anyone have any ideas why?


#2

Hi Arfy,

after you switched to Data Mode you should not use the function “adl_atSendResponse()” anymore… That is only used for AT mode. The first thing you do in data mode is

adl_atSendResponse ( ADL_AT_UNS, " ADL_FCM_EVENT_V24_DATA_MODE\r\n");

I think it crashes right there… But there could be other places where adl_atSendResponse is called in data mode… Just make sure you don’t use this function at all when in data mode and your program should work also in target mode.

Best Regards,
Jan


#3

Hi Jan,

Thanks for the advice, you are right that I shouldn’t use “adl_SendResponse” in Data mode. However that wasn’t the problem, and in fact the calls to the function were still executed but of course not sent on the Data port.

In the end I found that I should have declared the adl_fcmSubscribe handle as ‘Static’. So when the parameter was passed to the adl_fcmSwitchV24State() function the handle was not kept. No wonder it was crashing! :unamused:

regards,
Arfy


#4

Hi Arfy,

Thank you for the update!

That’s strange… You defined the handle as global variable for the whole application. This is not supposed to loose its value, is it?

Best Regards,
Jan


#5

Hi Jan,

I did some more investigation, and found that it wasn’t the handle but rather the char array for msg_test that was causing the problem (I’d made all my variables Static at the same time). There must be another variable of the same name in adl_fcmSwitchV24State(), but I think perhaps not of the same type. I think the Windows environment allows same name but different type variables to be declared (hence working in Debug mode) but not in OpenAT running as Target. Still, I guess it’s always better to declare all globals as Static type (including handles) to prevent any possibility of future OpenAT versions causing conflicts.

Regards,
Arfy


#6

Well I’m not surprised to see this kind of problems. I’ve had several headaching problems just because Visual Studio does not compile as it would do in Target mode. Wavecom should really issue a documentation with compilation differences or important notes between the platforms.


#7

Hi,

Are you using GCC?

I have seen a similar problem using GCC, the problem
is that GCC does not know that external code is going
to access msg_test, so it is optimized away.

Marking it static removes the problem, since this stops
it from being placed on the stack by the optimizer.

I don’t believe the ARM compiler would do this.

adl_fcmSendData probably saves a pointer to the data,
not the data itself. This reduces memory and CPU cycle
overhead considerably.

Most OpenAT calls that take pointer arguments require that
the pointer stay valid after the call returns.

Regards,
Nic


#8

Shouldn’t the volatile attribute fix this?