0
\$\begingroup\$

I am using LPCOpen (latest realese available for LPC4370) and the usb stack provided within it. I need to build a simple FSM to control the mcu with Matlab and send data from Matlab to the mcu and from the mcu to Maltab. (here another question from me on the same topic)

  • FSM: I'm using char as commands (e.g. Matlab sends 'o', the mcu starts data output
  • DATA TRANSFER: I'm sending data in bulks of 128 32 bits integers each

So as far as I understood I need to implement a CDC USB host.

LPCOPen provides the following examples to start with (and no documentation other than read-me files)

  • usbd_rom_cdc_uart: The example shows how to us USBD ROM stack to creates a CDC UART/Serial port bridge.

  • usbd_rom_cdc_vcom The example shows how to us USBD ROM stack to creates a virtual comm port.

  • usbd_rom_dfu_composite

  • usbd_rom_hid_generic

  • usbd_rom_hid_keyboard

  • usbd_rom_hid_mouse

  • usbd_rom_hid_sio

  • usbd_rom_libusb: The example shows how to us USBD ROM stack to create simple USB data pipes. This example provides libusbdevice encapsulation with simple to use API for non-USB experienced users to develop simple data-pipe applications. The example is tested with http://libusbk.sourceforge.net host side applications. The examples also shows how to handle WCID requests to install libusbk driver. Check https://github.com/pbatard/libwdi/wiki/WCID-Devices for more details.

  • usbd_rom_msc_ram: The example shows how to use USBD ROM stack to creates a USB MSC example that uses RAM. The device appears as unformatted disk with size as 32KB.

Among the above are two examples which I think could use: usbd_rom_cdc_uart and usbd_rom_cdc_vcom.

usbd_rom_cdc_uart is enterely IRQ based and it was not clear to me how I could send/receive data. it's main loop looks like:

while (1) {
    /* Sleep until next IRQ happens */
    __WFI();
}

So I started with usbd_rom_cdc_vcom which does a loop-back:

DEBUGSTR("USB CDC class based virtual Comm port example!\r\n");

while (1) {
    /* Check if host has connected and opened the VCOM port */
    if ((vcom_connected() != 0) && (prompt == 0)) {
        vcom_write("Hello World!!\r\n", 15);
        prompt = 1;
    }
    /* If VCOM port is opened echo whatever we receive back to host. */
    if (prompt) {
        rdCnt = vcom_bread(&g_rxBuff[0], 256);
        if (rdCnt) {
            vcom_write(&g_rxBuff[0], rdCnt);
        }
    }
    /* Sleep until next IRQ happens */
    __WFI();
}

So I tested this on a terminal and then tried to move on and use Matlab.

What I found more difficult doing the small messaging. Here some code snippets. From matlab side:

fwrite(serial_object, K_COEFF,  'int32');
if K_COEFF ~= fread(serial_object, 1, 'int32')
 error('out of sync');
 end
pause(0.0005)

fwrite(serial_object, L_COEFF,  'int32');
 if L_COEFF ~= fread(serial_object, 1, 'int32')
 error('out of sync');
end
pause(0.0005)

C counterpart:

/*SET K*/
while(!rdCnt)
{rdCnt = vcom_bread(&param_rxBuff, sizeof(int32_t));}
K_COEFF = param_rxBuff;
vcom_write((uint8_t*)&param_rxBuff, sizeof(int32_t));
param_rxBuff = 0;
rdCnt = 0;

/*SET L*/
while(!rdCnt)
{rdCnt = vcom_bread(&param_rxBuff, sizeof(int32_t));}
L_COEFF = param_rxBuff;
vcom_write((uint8_t*)&param_rxBuff, sizeof(int32_t));
param_rxBuff = 0;
rdCnt = 0;

where vcom_bread and vcom_write are usb stack calls.

Now, this is working. Sometimes.

Some other times the communication goes "out of sync" and Matlab just hangs on printing warnings about the microcontroller not responding. What I noticed is that this depends largely on timing and so also on the compiler settings: I am using arm-none-eabi-gcc and the more I optimize (e.g. O3) the less it works. Does anyone have similar experience of some kind? What should be the best way of interfacing Matlab with an mcu?

EDIT1: As suggested I tried to modify the matlab side:

fwrite(...)
pause(0.001);
flushoutput(serial_object);
flushinput(serial_object);
fread(...)

Unfortunately to no avail. Matlab is still warning me about unsuccessful read.

\$\endgroup\$
  • 1
    \$\begingroup\$ It's unclear here if you are using a fully buffered virtual serial channel with blocking reads, or something that more closely reflects what is actually going on at packet level, but you should probably start by figuring that out, and adapting the code to handle what can legitimately happen in each case. You might also use something like wireshark in USB monitoring mode. It's also unclear if your embedded USB stack will "pump itself in the background automatically" via interrupts alone or if you are obligated to call into it periodically to let it do so. \$\endgroup\$ – Chris Stratton Jul 29 at 14:10
  • \$\begingroup\$ Hi @ChrisStratton, thanks for the comment. I must say I'm quite a newbie when it comes to USB. What I know from the example that I started with is that I should use those 2 functions to read/write and that the stack operates in interrupt mode. Infact I can see an USB IRQ handler into the code. Does it make sense that the reliability depends on compiler settings like optimization? \$\endgroup\$ – a_bet Jul 29 at 18:04
  • \$\begingroup\$ Again, you need to take time to understand the actual behavior specified for the APIs you use. And use something like wireshark to see what is actually happening on the USB bus. You path to a solution will be to either recognize invalid assumptions by inspection of the code or to identify the specific undesired behavior in a log of communication and then trace that back to the ultimate cause. \$\endgroup\$ – Chris Stratton Jul 31 at 17:02
  • 1
    \$\begingroup\$ Lots of little calls are probably slow but for many uses aren't necessarily bad if you have sound synchronization logic. Note you could have a much simpler synchronization scheme if you used USB packets directly, as they give you a sense of framing that you won't really have with a serial API. But all you really need to do here is write sound wait for a result logic, make sure you handle the possibility of only some but not all bytes initially being available, and have some sort of giveup and retry in the case of gross failure. \$\endgroup\$ – Chris Stratton Aug 1 at 13:49
  • 2
    \$\begingroup\$ Read the Matlab documentation guidance on serial coms mathworks.com/help/matlab/matlab_external/… pay particular attention to synchronous vs. asynchronous modes and the Timeout property. The line-oriented textual examples won't apply (unless you change your format) but the binary one would. With an appropriate timeout you should be able to do a read that will block until it gets your data or gives up. Or you can check the available bytes yourself while checking the time, do the read once you see enough or make your own decision to give up. \$\endgroup\$ – Chris Stratton Aug 1 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.