Using UART to communicate with another board

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Using UART to communicate with another board

2,024 Views
johanandrade
Contributor III

Hey support,

Looking to see if someone can point me in the right direction. I have another board that is writing a message via UART when pressing a toggle button on a touchscreen.

The function in this board looks like this with the bold lines related to UART sent message:

void homeView::lightToggled()
{
bool new_state = lightSwitch.getState();
uint8_t Message[]="light state changed \n\r";

touchgfx_printf("lightToggled: %d\n", new_state);

g_sf_comms0.p_api->write(g_sf_comms0.p_ctrl, Message,sizeof(Message),5);

//inform Model through presenter
presenter->lightToggled(new_state);
}

Image 104.png

I'm now trying to apply this to the R41Z board (based on KW41Z) to receive this message and trigger an event to turn on an LED remotely that is connected to another R41Z board.

At the moment the R41Z board can turn on/off this LED remotely via the SW4 button.

static void APP_AppModeHandleKeyboard
(
uint32_t keyEvent
)
{
switch(keyEvent)
{
case gKBD_EventPB1_c:
/* Data sink create */
(void)NWKU_SendMsg(APP_SendDataSinkCreate, NULL, mpAppThreadMsgQueue);
break;
#if gKBD_KeysCount_c > 1
case gKBD_EventPB2_c:
/* Report temperature */
//(void)NWKU_SendMsg(APP_ReportTemp, NULL, mpAppThreadMsgQueue);
//(void)NWKU_SendMsg(APP_SendExtLedOff, NULL, mpAppThreadMsgQueue);
{
/* Open the damper remotely */
static bool_t isDamperOn = FALSE;
if(isDamperOn) {
(void)NWKU_SendMsg(APP_SendDamperStop, NULL, mpAppThreadMsgQueue);
isDamperOn = FALSE;
} else {
(void)NWKU_SendMsg(APP_SendDamperOpen, NULL, mpAppThreadMsgQueue);
isDamperOn = TRUE;
}
}
break;
case gKBD_EventPB3_c:
/* Remote led RGB - on */
//(void)NWKU_SendMsg(APP_SendLedRgbOn, NULL, mpAppThreadMsgQueue);
//(void)NWKU_SendMsg(APP_SendExtLedOn, NULL, mpAppThreadMsgQueue);
{
/* toggle external LED on/off with same SW4 */
static bool_t isLedOn = FALSE;
if(isLedOn){
(void)NWKU_SendMsg(APP_SendExtLedOff, NULL, mpAppThreadMsgQueue);
isLedOn = FALSE;
} else {
(void)NWKU_SendMsg(APP_SendExtLedOn, NULL, mpAppThreadMsgQueue);
isLedOn = TRUE;
}
}
break;

I see that the project (frdmkw41z_wireless_examples_thread_router_eligible_device) has several UART files and functions included already (fsl_lpuart, UART_Adapter, etc.). Which functions should I be using to setup the UART? Do I set it to use the same baudrate as my other device (9600)? Would this serial operation be completely separate from static void APP_AppModeHandleKeyboard? Thanks!

Labels (2)
6 Replies

1,580 Views
ovidiu_usturoi
NXP Employee
NXP Employee

Hi Johan,

I double checked the baudrate configuration when the shell is used. This is actually set in shell_init  by calling Serial_SetBaudRate. (file shell.c). Please update the value for SHELL_IO_SPEED by changing APP_SERIAL_INTERFACE_SPEED to 9600 as you are using on the  application processor.

The following define is set in board.h file.

#define APP_SERIAL_INTERFACE_SPEED (9600).

Regards,

Ovidiu

0 Kudos

1,580 Views
johanandrade
Contributor III

I changed the configurations via APP_SERIAL_INTERFACE but it wasn't working. However, I realized I had to Ground both devices to each other. Everything is working now. Thank you!

0 Kudos

1,580 Views
ovidiu_usturoi
NXP Employee
NXP Employee

Hi Johan :smileyhappy:,

I assume that the serial communication will be via J11 connector (pins  - PTC6, PTC7) of the R41Z evaluation board.

Considering that on the USB connection, you already have a shell communication (THREAD_USE_SHELL define enabled), the easiest way is to switch from USB connection to J11 connector. This could be done by updating the Board_InitLPUART (pin_mux.c file) function like below:

void BOARD_InitLPUART(void)
{
     CLOCK_EnableClock(kCLOCK_PortC);                                       /* Port C Clock Gate Control: Clock enabled */

     PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt4);            /* PORTC6 (pin 42) is configured as UART0_RX */
     PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt4);            /* PORTC7 (pin 43) is configured as UART0_TX */
     SIM->SOPT5 = ((SIM->SOPT5 &
             (~(SIM_SOPT5_LPUART0RXSRC_MASK)))                        /* Mask bits to zero which are setting */
               | SIM_SOPT5_LPUART0RXSRC(SOPT5_LPUART0RXSRC_LPUART_RX)
             );

}

The shell module contains a list  of commands located in shell_ip.c file (aShellCommands structure). You can update this structure by adding your command and registering a callback, something like:

const cmd_tbl_t aShellCommands[] =

{

   ....

    {
        "light", SHELL_CMD_MAX_ARGS, 0, SHELL_LightCb
#if SHELL_USE_HELP
        ,"Light Commands",
        "Commands for Light \r\n"
        "   light state changed\r\n"
#endif /* SHELL_USE_HELP */
#if SHELL_USE_AUTO_COMPLETE
        ,NULL
#endif /* SHELL_USE_AUTO_COMPLETE */
    },

...

}

where SHELL_LightCb looks like:

   

static int8_t SHELL_LightCb ( uint8_t argc,   char *argv[] )

{

          if(!strcmp(argv[1], "state"))
          {

                if(!strcmp(argv[2], "changed"))

                {

                        /* put you code here to handle the event */

                }

          }

}

If you are using a baud rate of 9600, we will have to set the same on KW41. This could be done by updating mFsciSerials structure (from app_init.c) -> .baudrate = gUARTBaudRate9600_c,

Please consider that by default, from our stack, will be also some data events sent from KW41 via shell interface (like some status events - "joining..., node joined ..."-). You can handle or drop these events on the second microcontroller (the one with touch display associated).

The second approach is to init a second uart interface. My recommendation is to look at UART_Adapter.c file. This file contains  the API required for initializing and controlling the UART instance.

Regards,

Ovidiu

1,580 Views
johanandrade
Contributor III

Hi Ovidiu,

Thanks so much for the detailed explanation. Yes I am using PTC6/PTC6 as the serial communication UART between the R41Z and the touchscreen board SK-S7G2.

The void BOARD_InitLPUART(void) function already had the same configuration as you provided so didn't need to do anything there it seems.

I'm now writing the application part for static int8_t SHELL_LightCb. I've been trying a similar approach as when I was using the SW4/SW3 to handle the events.

static int8_t SHELL_LightCb
(
uint8_t argc,
char *argv[]
)
{
if(!strcmp(argv[1], "state"))
{
if(!strcmp(argv[2], "changed"))
{
static bool_t isLedOn = FALSE;
if(isLedOn){
//(void)NWKU_SendMsg(APP_SendExtLedOff, NULL, mpAppThreadMsgQueue);
NWKU_SendMsg(SHELL_SendExtLedOff, NULL, pmMainThreadMsgQueue);
isLedOn = FALSE;
} else {
//(void)NWKU_SendMsg(APP_SendExtLedOn, NULL, mpAppThreadMsgQueue);
NWKU_SendMsg(SHELL_SendExtLedOn, NULL, pmMainThreadMsgQueue);
isLedOn = TRUE;
}
}
}
}

/*!*************************************************************************************************
\private
\fn static void SHELL_SendExtLedOff(void *param)
\brief This function is used to send an external Led Off command over the air.

\param [in] param Not used
***************************************************************************************************/
static void SHELL_SendExtLedOff
(
void *param
)
{
uint8_t aCommand[] = {"off"};
//APP_SendLedCommand(aCommand, sizeof(aCommand));

SHELL_CoapSend(aCommand, sizeof(aCommand));
}

Should I be using the SHELL functions that are defined? SHELL_CoapSend seems to be the function used for commands. However, I think the way I'm calling the function with my arguments are wrong. Basically I would need to send the following COAP message after it reads the message "light state changed" from my other device. How would it know the IP address of the destination node though without entering it manually?

help coap
coap - Send CoAP message
coap <reqtype: CON/NON> <reqcode (GET/POST/PUT/DELETE)> <IP addr dest> <URI path>
<payload ASCII>
Example: coap CON POST 2001::1 /led off

0 Kudos

1,580 Views
ovidiu_usturoi
NXP Employee
NXP Employee

Hi Johan,

If you already have the functionality on switch events, means that you know the destination.  The easiest way is to reuse that functions. For example:

-  consider the serial interface callback (shell_ip.c file):

extern void APP_LightShellEventReceived(); /* this will be defined in your app file */

/* callback for shell light event */

static int8_t SHELL_LightCb ( uint8_t argc,   char *argv[] )

{

          if(!strcmp(argv[1], "state"))
          {

                if(!strcmp(argv[2], "changed"))

                {

                      APP_LightShellEventReceived();

                }

          }

}

where APP_LightShellEventReceived() is define in the same place with the switch control functions (e.g....router_eligible_device_app..):

void APP_LightShellEventReceived(void)

{

     static bool_t isLedOn = FALSE;
     if(isLedOn)

     {
            (void)NWKU_SendMsg(APP_SendExtLedOff, NULL, mpAppThreadMsgQueue);
            isLedOn = FALSE;
      }

      else

       {
              (void)NWKU_SendMsg(APP_SendExtLedOn, NULL, mpAppThreadMsgQueue);
               isLedOn = TRUE;
      }

}

Considering that the light could be controlled via a switch or via serial interface, my recommendation is to put the  isLedOn variable as global in the file, instead of using static variable inside the functions.

The second approach could be from display to send a formatted serial command ..something like you already mentioned (coap CON POST 2001::1 /led off) and in this case it will be no change in the shell_ip.c file.

Regards,

Ovidiu

1,580 Views
johanandrade
Contributor III

I've applied the application code but using the touchscreen device toggle button is not triggering the event at the moment. To check if the functions are working correctly I've been testing the shell command via Tera Term.

Image 001.png

Typing the "light state changed" command triggers the event and turns on the remote LED. I'm wondering if my baudrate settings are incorrect. There are several .baudrate lines available in the mFsciSerials structure. The one I set to 9600 is for an interface type of gSerialMgrUSB_c. I've noticed in the seriallnferfaeType_t structure available in SerialManager.h there is a "gSerialMgrUart_c"  available. Should I be using this one instead of USB or is there a configuration available inside app_int.c already? Thanks as always.

#if THREAD_USE_THCI
/* FSCI Interface Configuration structure */
static const gFsciSerialConfig_t mFsciSerials[] =
{
/* Baudrate, interface type, channel number */
#if THCI_USB_ENABLE
{
//.baudrate = gUARTBaudRate115200_c,
.baudrate = gUARTBaudRate9600_c,
.interfaceType = gSerialMgrUSB_c,
.interfaceChannel = 0,
.virtualInterface = 0
},
#elif THCI_SPI_ENABLE
{
.baudrate = gSPI_BaudRate_1000000_c,
.interfaceType = gSerialMgrSPIMaster_c,
#if defined(FRDM_KW41Z) || defined(USB_KW41)
.interfaceChannel = 1,
#else
.interfaceChannel = 0,
#endif
.virtualInterface = 0
},
#else
{
.baudrate = gUARTBaudRate115200_c,
.interfaceType = APP_SERIAL_INTERFACE_TYPE,
.interfaceChannel = APP_SERIAL_INTERFACE_INSTANCE,
.virtualInterface = 0
},
#if gHybridApp_d
{
.baudrate = gUARTBaudRate115200_c,
.interfaceType = APP_SERIAL_INTERFACE_TYPE,
.interfaceChannel = APP_SERIAL_INTERFACE_INSTANCE,
.virtualInterface = 1
},
#endif
#endif
};
#endif

0 Kudos