Data misalignment in USB Stack code on the iMX6SL (from Baremetal SDK 1.1)

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

Data misalignment in USB Stack code on the iMX6SL (from Baremetal SDK 1.1)

Jump to solution
2,655 Views
nathanpalmer
Contributor IV

I am trying to run the example USB Stack code from the Baremetal SDK on the iMX6SL. I had hoped to use the CDC stack in an application but I cannot get the example code to run:

.../sdk/common/usb_stack/Device/app/cdc/virtual_com.c

I cannot get this code to run, does the usb_stack work with the iMX6SL?  If not, is there any example code for the iMX6SL?  I see the the sdk/drivers/usb/src/ files, but that code is not setup to handle an interrupt driven flow and it also is very specific the the HID class of devices. I has hoping to quickly get a CDC class going.

There is a packed structure that is defined in usb_devapi.h:

typedef struct _USB_EP_STRUCT
{
    uint_8          ep_num;      /* endpoint number         */
    uint_8          type;        /* type of endpoint        */
    uint_8          direction;   /* direction of endpoint   */
    USB_PACKET_SIZE    size __attribute__ ((packed))  ;  /* buffer size of endpoint */
} __attribute__ ((packed))  USB_EP_STRUCT, *USB_EP_STRUCT_PTR;

That is causing bad code to be generated.  Using ARM gcc 4.8.3 creates code in several places that tries to access the 'size' attribute (which is a 16-bit halfword) and causes a misaligned data abort on the iMX6SL

For example, in the reset handler:

usb_class.c:     void USB_Reset_Service (...)

and

usb_driver.c:     uint_8 _usb_device_init_endpoint (...)

   │0x80086c48 <_usb_device_init_endpoint+88>       ldrb   r3, [r11, #-25]
   │0x80086c4c <_usb_device_init_endpoint+92>       strb   r3, [r11, #-20]  
>│0x80086c50 <_usb_device_init_endpoint+96>       ldrh   r3, [r11, #-28] ;
   │0x80086c54 <_usb_device_init_endpoint+100>      strh   r3, [r11, #-17] ; <------------- This is a half-word instruction on a byte aligned data address: 0x82272697

Note:

I have tried to call the following, but I still get the error.

//! @brief Disable aborts on unaligned accesses.
void disable_strict_align_check(void);

Labels (2)
Tags (5)
0 Kudos
Reply
1 Solution
2,123 Views
nathanpalmer
Contributor IV

After digging through the SDK code, it looks like the final two changes I had to make were to invalidate/clean the cache before reading or writing to the data in the queuehead and to disable zero length transfers (ZLT) for incoming transfers, apparently windows does not support ZLT with the specified driver.

View solution in original post

0 Kudos
Reply
6 Replies
2,123 Views
nathanpalmer
Contributor IV

I am still struggling with this code for USB CDC support.   Can someone tell me what the best source is for a bare metal USB stack for iMX6SL (ported and tested for iMX6)?

The one in the usb_stack directory does not seem to work well.  For any non-trivial use I am getting the following error on reading data from Windows:

received usb error irq on device 0

And It will not even enumerate in Linux.

0 Kudos
Reply
2,124 Views
nathanpalmer
Contributor IV

After digging through the SDK code, it looks like the final two changes I had to make were to invalidate/clean the cache before reading or writing to the data in the queuehead and to disable zero length transfers (ZLT) for incoming transfers, apparently windows does not support ZLT with the specified driver.

0 Kudos
Reply
2,123 Views
Rob_iMX6
Contributor II

Hi Nathan

Many thanks for your posts on this subject -- there is not much help for bare metal programmers... :-(

How did you get past the "received usb error irq on device 0" ? If I type slowly on the terminal, then the characters get correctly echoed;

However, if I enter several characters (by pasting a string into the terminal), the iMX6 runs into that error. Where did you disable the ZLT? I tried all of them I found, but without success.

Thanks and regards,

-Rob

0 Kudos
Reply
2,123 Views
nathanpalmer
Contributor IV

Sorry, I don't have the code handy now, but I believe that I delayed priming the next transfer by ~ 9/115200 seconds to emulate the throughput of an RS232 @ 115200 baud, That kept the windows side from bombarding the mx6 with data. 

0 Kudos
Reply
2,123 Views
Rob_iMX6
Contributor II

Hi Nathan

In the meantime I have manged to get the virtual com example running -- it needed quite some debugging hours to get it running stable.

Here are some notes for our bare-metal fellows:

  • ZLT is disabled by setting the corresponding bit. in the function usbd_prime_ep, make sure that the bit ZLT is set for OUT transfers, when total_bytes equals the packet size. And the ZLT-bit is cleared for IN directions, when total_bytes equals the packet size. (to work with windows usbser.sys)
  • the USB code in the SDK was obviously written for a processor without caching. Hence it only works with data caches disabled. [Freescale: Who would ever run a iMX6 with data caches turned off?? Please provide a better SDK!]
  • enabling data caches requires to invalidate the buffers upon an OUT transfer and clean-operation for IN transfers. Make sure that your buffers are 32byte aligned, otherwise you will observe strange behavior! Make sure that you only invalidate the size of your buffer and not more. You need to do the cache maintenance operations on both L1 and L2 cache! Look out for the L2C310 patch for the SDK! [Freescale: why not providing an update?]
  • the control endpoint buffer is tricky: It keeps 1 word of the request data in the first word. Invalidating the buffer will also invalidate two words. Therefore make sure, that your the static variable ext_req_to_host is
    1.    size of 96 bytes
    2.    aligned to 32 bytes
    3.   and has always an offset of 24 bytes, which insures that the data for an OUT transaction will by aligned to 32bytes (for your cache invalidation). For example:
                in file usb_framework.c:
                #define EXT_REQ_TO_HOST_OFFSET 24
                (void)memcpy(ext_req_to_host + EXT_REQ_TO_HOST_OFFSET, &g_setup_pkt, USB_SETUP_PKT_SIZE);

  • I have observed problems with unaligned 16bit word accesses going wrong. Therefore I have changed USB_PACKET_SIZE to uint_8 -- virtual com does not support packets larger than 64bytes anyway.
  • Microsoft windows usbser.sys is not a good driver. It easily looses connection (see many discussions on the web). It is limited to 64byte packets. We have not managed to get more than 64kBytes/s transfer rate (1000 packets per second).
  • OUT transaction priming takes place only after an IN transaction, which is wrong. If you have more data to send than to receive, you will get errors like "cannot get dTD!". And if you receive more than you send, the connection will starve, because there is no transaction descriptor left. Hence: The example is pretty useless.

Conclusion:

- do not use Freescale's SDK for USB

- do not use Microsofts' usbser.sys (aka virtual com).

- ask Freescale for abetter quality SDK!

Regards,

-Urs

0 Kudos
Reply
2,123 Views
nathanpalmer
Contributor IV

UPDATE:  I was able to get past my previous problem by enabling the MMU and DISABLING ARM Strict Alignment checking:

    //! @brief Disable aborts on unaligned accesses.
    void disable_strict_align_check(void);

The disable_strict_align_check(void) was failing before because I had the MMU turned off for debugging.  

It looks like the class API changed some and the CDC Demo App was not updated.  I have made some progress with the CDC demo, but I had to make the following updates:

Index: cpu/imx6sl/sdk/common/usb_stack/Device/app/cdc/user_config.h
===================================================================
--- cpu/imx6sl/sdk/common/usb_stack/Device/app/cdc/user_config.h    (revision 535)
+++ cpu/imx6sl/sdk/common/usb_stack/Device/app/cdc/user_config.h    (working copy)
@@ -23,7 +23,7 @@
#if (defined MCU_MK70F12) || (defined __MCF52277_H__)
    #define  HIGH_SPEED_DEVICE    (0)
#else
-    #define  HIGH_SPEED_DEVICE    (0)
+    #define  HIGH_SPEED_DEVICE    (1)
#endif

#if (defined MCU_MK20D7) || (defined MCU_MK40D7)
Index: cpu/imx6sl/sdk/common/usb_stack/Device/app/cdc/virtual_com.c
===================================================================
--- cpu/imx6sl/sdk/common/usb_stack/Device/app/cdc/virtual_com.c    (revision 535)
+++ cpu/imx6sl/sdk/common/usb_stack/Device/app/cdc/virtual_com.c    (working copy)
@@ -26,6 +26,7 @@
#include "usb_cdc.h"        /* USB CDC Class Header File */
#include "virtual_com.h"    /* Virtual COM Application Header File */
#include <stdio.h>
+#include "user_config.h"

#if (defined _MCF51MM256_H) || (defined _MCF51JE256_H)
#include "exceptions.h"
@@ -51,7 +52,7 @@
  * Global Variables
  ****************************************************************************/
#if HIGH_SPEED_DEVICE
-uint_32 g_cdcBuffer[DIC_BULK_OUT_ENDP_PACKET_SIZE>>1];
+uint_8 g_cdcBuffer[DIC_BULK_OUT_ENDP_PACKET_SIZE>>1];
#endif

/*****************************************************************************
@@ -256,11 +257,15 @@
    }
    else if((event_type == USB_APP_SEND_COMPLETE) && (start_transactions == TRUE))
    {
+        /**
+        * Looks like the API changed, Class functions expect a pointer to the controller ID
+        */
+        uint8_t TEMP_CONTROLLER_ID = CONTROLLER_ID;
        /* Previous Send is complete. Queue next receive */
#if HIGH_SPEED_DEVICE
-        (void)USB_Class_CDC_Interface_DIC_Recv_Data(CONTROLLER_ID, g_cdcBuffer, DIC_BULK_OUT_ENDP_PACKET_SIZE);
+        (void)USB_Class_CDC_Interface_DIC_Recv_Data(&TEMP_CONTROLLER_ID, g_cdcBuffer, DIC_BULK_OUT_ENDP_PACKET_SIZE);
#else
-        (void)USB_Class_CDC_Interface_DIC_Recv_Data(CONTROLLER_ID, NULL, 0);
+        (void)USB_Class_CDC_Interface_DIC_Recv_Data(&TEMP_CONTROLLER_ID, NULL, 0);
#endif
    }

@@ -300,7 +305,9 @@
        }
        else if(event_type == USB_APP_CDC_CARRIER_DEACTIVATED)
        {
-            start_transactions = FALSE;
+            //start_transactions = FALSE;
+            // Windows terminal + CDC driver do not send the CARRIER_ACTIVATED, so set it to true anyway for testing
+            start_transactions = TRUE;
        }
    }
    return;
Index: cpu/imx6sl/sdk/common/usb_stack/Device/source/driver/usb_devapi.h
===================================================================
--- cpu/imx6sl/sdk/common/usb_stack/Device/source/driver/usb_devapi.h    (revision 535)
+++ cpu/imx6sl/sdk/common/usb_stack/Device/source/driver/usb_devapi.h    (working copy)
@@ -313,7 +313,8 @@
}ALIGN USB_EP_STRUCT, *USB_EP_STRUCT_PTR;

#if (defined(__CWCC__)||defined(__GNUC__))
-    #pragma options align = reset
+    //#pragma options align = reset
+    #pragma pack()
#elif defined(__IAR_SYSTEMS_ICC__) || defined(__CC_ARM)
    #pragma pack()
#endif

0 Kudos
Reply