This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AM3352: Reading USB DevCtl crashes system

Part Number: AM3352
Other Parts Discussed in Thread: SYSBIOS, AM1808, STARTERWARE-SITARA

Tool/software: TI-RTOS

I'm reading from the USB Device Control register using the HWREG macro.  When I do so and the device is using the CDC driver it hangs the system and I haven't been able to get any relevant info about why it is crashing.

The statement that hangs things up is the following:

Usb_DevCtl = /* Crash --> */HWREG(USB0_BASE + USB_O_DEVCTL);

The constants are defined as

#define USB0_BASE SOC_USB_0_BASE

#define SOC_USB_0_BASE (0x47401400)

#define USB_O_DEVCTL 0x00000060 // USB Device Control

* I've verified through serial port that USB0_BASE + USB_O_DEVCTL does in fact equate to 0x47401460 which is correct

* If I bypass the HWREG call, everything works normally (except that I don't get the correct status I'm looking for from the Dev Ctl register of course)

* This is only a problem if the CDC driver is loaded.  Code works just fine if I use the USB device driver that does not use CDC.  Does use of the CDC driver somehow make USB_O_DEVCTL not readable?

* There is no other crash info.  When running in the debugger it just vectors off with no context info available

I'm reading this register just to look at bit 3 to see if there is a cable connected and there is something at the other end of the USB cable controlling the device.  If there is some other simple way to detect if there is life on the other end of the USB cable I'm OK with making a change but I would have expected that simply reading from a register is pretty darn simple and would not have issues (and it doesn't unless the CDC driver is running).

Kevin Jennings

  • Since I haven't heard back from anyone about why simply reading from the USB Dev Ctl register would crash the processor, is there any other way for a USB device to detect if there is a host physically connected supplying VBUS voltage?

  • Reading from the 'USB General Interrupt Status' (USB_O_IS) using HWREG() macro produces the bad behavior as reading from USB_O_DEVCTL.
  • Hi,

    I am not sure what code base you are referring to. Starterware is obsolete (if you use it) and AM335x USB is supported in Processor SDK RTOS. The latest is 5.3 release. From the USB driver code:
    #define SOC_USB_0_BASE (0x47401400)
    #define USB_O_DEVCTL 0x00000060 // USB Device Control

    So the base address and offset are correct. We have code read this register:

    uint32_t
    USBModeGet(uint32_t ulBase)
    {
    /* Check the arguments. */
    ASSERT((ulBase == USB0_BASE)||(ulBase == USB1_BASE));

    /* Checks the current mode in the USB_O_DEVCTL and returns the current
    * mode.
    * USB_OTG_MODE_ASIDE_HOST: USB_DEVCTL_HOST | USB_DEVCTL_SESSION
    * USB_OTG_MODE_ASIDE_DEV: USB_DEVCTL_SESSION
    * USB_OTG_MODE_BSIDE_HOST: USB_DEVCTL_DEV | USB_DEVCTL_SESSION |
    * USB_DEVCTL_HOST
    * USB_OTG_MODE_BSIDE_DEV: USB_DEVCTL_DEV | USB_DEVCTL_SESSION
    * USB_OTG_MODE_NONE: USB_DEVCTL_DEV */
    return(HWREGB(ulBase + USB_O_DEVCTL) &
    (USB_DEVCTL_DEV | USB_DEVCTL_HOST | USB_DEVCTL_SESSION |
    USB_DEVCTL_VBUS_M));
    }

    uint32_t
    USBHostSpeedGet(uint32_t ulBase)
    {
    /* Check the arguments. */
    ASSERT((ulBase == USB0_BASE)||(ulBase == USB1_BASE));

    /* After Reset , Host negitiates the speed by Chirp logic and then sets this bit */
    if(HWREGB(ulBase + USB_O_POWER) & USB_POWER_HS_MODE)
    {
    return(USB_HIGH_SPEED);
    }

    /* If the Full Speed device bit is set, then this is a full speed device. */
    if(HWREGB(ulBase + USB_O_DEVCTL) & USB_DEVCTL_FSDEV)
    {
    return(USB_FULL_SPEED);
    }

    /* If the Low Speed device bit is set, then this is a low speed device. */
    if(HWREGB(ulBase + USB_O_DEVCTL) & USB_DEVCTL_LSDEV)
    {
    return(USB_LOW_SPEED);
    }

    /* The device speed is not known. */
    return(USB_UNDEF_SPEED);
    }

    We don't have any issue.

    Regards, Eric
  • Eric,

    When I try calling USBModeGet(USB0_BASE) it crashes in the same way when it is executing the HWREGB macro. It looks like it is getting into exception handler code since I jump to function ti_sysbios_family_arm_exc_Exception_excHandlerDataAsm__I when I step through the code using 'Assembly Step Into'. The specific instruction is when the USB register is read. Specifically, this source and compiled code

    unsigned int Usb_DevCtl = /* Crash -> */HWREG(USB0_BASE + USB_O_DEVCTL);
    807d4564: E59FCFA0 ldr r12, [pc, #0xfa0]
    807d456c: E59C1000 ldr r1, [r12] <-- Executing this instruction causes the exception

    At the point where the exception occurs, R12=0x47401460, R1=0. So reading from address 0x47401460 is causing some exception but this exception is only occurring when the CDC driver has been started. Is there something in that driver that causes the USB Core registers like DEVCTL to be inaccessible and cause an exception? If so, what is the procedure for determining if the cable is connected when that driver is running?

    You didn't mention whether you have the CDC driver loaded on your side when you did your testing. I suspect that is important.

    Kevin Jennings
  • See last posting
  • Hi,

    We don't support USB CDC driver in AM335x RTOS. It is planned but the implementation is pushed back. What software package you are using? I assume that MMU is setup properly as you need to access other USB registers around the same region.

    Your goal is " is there any other way for a USB device to detect if there is a host physically connected supplying VBUS voltage?" Let me check.

    Regards, Eric
  • Eric,

    I'm using the USB CDC driver that looks like it is from the AM1808 StarterWare USB library. I don't see any version info in the source code so I've copied the header from usbdcdc.c at the end of the post. I realize this is no longer supported code but that's all we have for CDC from TI until the RTOS supports it sometime down the road.

    I'm not sure which USB registers are actually accessible but both the device control and interrupt status registers are in the 'USB Core' range of registers but both of them cause what appears to be the same exception.

    I didn't see anything in usbcdc.c that looked like it would return some status indicating that USB was alive and running but maybe you will have better luck.

    Kevin Jennings

    //*****************************************************************************
    //
    // usbdcdc.c - USB CDC ACM (serial) device class driver.
    //
    // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved.
    // Software License Agreement
    //
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    //
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    //
    // This is part of AM1808 StarterWare USB Library and reused from revision 6288
    // of the Stellaris USB Library.
    //
    //*****************************************************************************
  • Forgot to add that if I simply don't read from the device control register that the USB interface works just fine, no issues with the CDC driver. We have been using this code for a number of years. The only thing 'new' in the software is the attempt to add in something that detects whether the USB cable is attached so that it can be reported back up our firmware stack. That new code does work in another implementation that uses USB but does not use CDC driver.

    Lastly, I don't think there is any race condition between CD and this USB detection code. I've put in up to a 15 second delay before it starts to read Device Control register and still generates an exception.

    Kevin
  • Kevin,

    >>>>>unsigned int Usb_DevCtl = /* Crash -> */HWREG(USB0_BASE + USB_O_DEVCTL);>>>>>>>> This is a8-bit register, not 32-bit.
    Will uint8_t temp = (*((volatile uint8_t *)(USB0_BASE + USB_O_DEVCTL))) work?

    Regards, Eric
  • No difference using uint_8 type.  The problem is not when the data gets stored, it's when the USB Device Control register (or Interrupt Status register) gets read.  The modified source and compiled code is shown below.

    802 uint8_t Usb_DevCtl = /* Crash -> */HWREG(USB0_BASE + USB_O_DEVCTL);
    807d4564: E59FCFA4 ldr r12, [pc, #0xfa4]
    807d4568: E59CC000 ldr r12, [r12] <--- Causes exception
    807d4570: E6EF107C uxtb r1, r12

    R12=0x47401460 (uSB Device Control address) at time of crash.

    Kevin Jennings

  • In the exception handler there is a variable excContextp that has the value shown at the end of this post. I don't know what it all means but both the 'r12' and 'dfar' elements have the value 0x47401460 which is the address of the USB Device Control register. This matches with what I had posted earlier that the reading of memory 0x47401460 is causing an exception.

    Further stepping through and spelunking sysbios Exception.c shows that the 'excContextp->type' is 'Exception_Type_DataAbort' which then causes the following function to be called 'Error_raise(0, Exception_E_dataAbort, pc, excStack[2]);'

    Unfortunately, I still know why using the CDC driver causes the USB Core registers to no longer be readable or how to call into the CDC driver to see if there is life at the other end of the USB cable (i.e. Vbus input is being driven to 5V).

    excContextp struct ti_sysbios_family_arm_exc_Exception_ExcContext * 0x8070A6AC {threadType=ti_sysbios_BIOS_ThreadType_Hwi,threadHandle=0x00000000,threadStack=... Register R4
    *(excContextp) struct ti_sysbios_family_arm_exc_Exception_ExcContext {threadType=ti_sysbios_BIOS_ThreadType_Hwi,threadHandle=0x00000000,threadStack=0x00000000,threadStackSize=... 0x8070A6AC
    threadType enum ti_sysbios_BIOS_ThreadType ti_sysbios_BIOS_ThreadType_Hwi 0x8070A6AC
    threadHandle void * 0x00000000 0x8070A6B0
    threadStack void * 0x00000000 0x8070A6B4
    threadStackSize unsigned int 0 0x8070A6B8
    type enum ti_sysbios_family_arm_exc_Exception_Type 0x00 0x8070A6BC
    r0 void * 0x000000C9 0x8070A6C0
    r1 void * 0x00000000 0x8070A6C4
    r2 void * 0x0000F7C4 0x8070A6C8
    r3 void * 0x00000000 0x8070A6CC
    r4 void * 0x807937E4 0x8070A6D0
    r5 void * 0x8085C2B8 0x8070A6D4
    r6 void * 0x807A0B5C 0x8070A6D8
    r7 void * 0x80794394 0x8070A6DC
    r8 void * 0x80794438 0x8070A6E0
    r9 void * 0xFFFFFFFF 0x8070A6E4
    r10 void * 0xFFFFFFFF 0x8070A6E8
    r11 void * 0xFFFFFFFF 0x8070A6EC
    r12 void * 0x47401460 0x8070A6F0
    sp void * 0x8011DA40 0x8070A6F4
    lr void * 0x00000000 0x8070A6F8
    pc void * 0x807D4568 0x8070A6FC
    psr void * 0x00000000 0x8070A700
    dfsr void * 0x00001008 0x8070A704
    ifsr void * 0x00000000 0x8070A708
    dfar void * 0x47401460 0x8070A70C
    ifar void * 0x00000000 0x8070A710
  • Is there some sort of power management bit (or clock management or 'other' management) that needs to be enabled prior to accessing USB core registers?
  • If I am interpreting the Tech Ref correctly, USB is part of the peripheral power domain, the power status register should be readable via the following:
    unsigned int PowerStatus = HWREG(0x44E00C08); // or HWREG(SOC_PRM_PER_REGS+PRM_PER_PM_PER_PWRSTST)

    It does read without issue and reports that the Peripheral Power Status register is set to 0x01E60007 which, according to the Tech Ref is the reset value. Interpreting the bits, the peripheral power state and logic state are both 'On' .

    So what can cause a data abort in this situation where the address being referenced, 0x47401460, is valid?
  • Hi Kevin

    We are not aware of any read restriction with the DEVCTL register. It should be readable. Are you running the USB as host mode or device mode?

    Can you manually read the address 0x47401460 from the Memory Browser in Code Composure Studio?

    Best regards

    Thanh

  • What does your MMU table looks like? We have a section for USBSS. Can you read any of the USBSS register starting from 0x47401400?
  • I'm running as a USB device. I have two programs that I can test, one that uses the CDC driver, the other does not. For both programs, when I manually read 0x47401460 from the Memory Browser in Code Composure Studio it shows up as ????????. I'm stopping at the same point in the code when I do the memory browser read.

    Kevin Jennings
  • Thanks. That looks like either USB is not powered up, USB clock is not turned on, or MMU has not been setup for this USB region. Are you using Processor SDK?
  • To your earlier post:  Nothing from 0x47401400, USB0 Core is readable (shows up as ???????? in the memory browser).  Nothing from 0x47400000 USB SS is readable either.

    To your later post about USB is not powered up, USB clock is not turned on, or MMU has not been setup for this USB region:  USB must be powered on and the clock running.  The two programs that I'm using are working functional code that have been in production for several years.  The only thing that I have added is to get status using HWREG(USB0_BASE + USB_O_DEVCTL), mask off bit 3 and pass that up to through our firmware stack to report on whether or not there is something connected to USB.  The one program uses the USB CDC driver, the other does not.  Since both programs are completely functional without the modification to add the single "HWREG(USB0_BASE + USB_O_DEVCTL)" statement, the problem can't be like USB not powered or clocks not running.

    I do have to correct one statement from my previous post.  USB0 Core registers starting at 0x47401400 ARE readable in Code Composer's memory browser window when I'm running the program that does not use the USB CDC driver.

    Since the data abort exception is happening right on the assembler instruction that performs the read from memory location 0x47401460 (aka USB0_BASE + USB_O_DEVCTL) this implies that the system is thinking that the address is invalid to be read from.  Since this only happens when using the USB CDC driver it suggests one of the two scenarios:

    - The non-CDC driver program does something to enable memory access to USB registers that the USB CDC driver program does not enable

    - The USB CDC driver does something to disable memory access to USB registers

    In either scenario, the fix would be to make sure that memory access to USB registers are enabled in the USB CDC program.  So now the question would be what is the mechanism for enabling/disabling access to USB registers?  If the USB CDC driver is intentionally disabling access, then a further question would be 'Why?'

    Kevin Jennings

  • Kevin,

    So, program 1 without CDC, program 2 with CDC

    - Both programs 1 and 2 functioning well
    - Program 1: USB0 Core registers starting at 0x47401400 ARE readable in Code Composer's memory browser window
    - Program 2: USB0 Core registers starting at 0x47401400 ARE read as ?????? in Code Composer's memory browser window

    Do you have MMU setup for 0x47401400 region in program 2? Just double check?

    Regards, Eric
  • Eric,

    Where are the MMU registers and where can I find the documentation on them? Searching the Technical Reference presents nothing useful when searching for 'Memory Management Unit' but searching for 'mmu' produces too many hits for words like 'communication'.

    Kevin
  • Hi,

    Do you use RTOS or baremetal?

    If RTOS, there would be something like below in the configuration:

    Mmu.enableMMU = true;

    // Force peripheral section to be NON cacheable strongly-ordered memory
    var peripheralAttrs = {
    type : Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
    tex: 0,
    bufferable : false, // bufferable
    cacheable : false, // cacheable
    shareable : false, // shareable
    noexecute : true, // not executable
    };

    // Define the base address of the 1 Meg page
    // the peripheral resides in.
    var peripheralBaseAddr = 0x44e00400;

    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
    peripheralBaseAddr,
    peripheralAttrs);


    // Define the base address of the 1 Meg page
    // the peripheral resides in.
    var peripheralBaseAddr = 0x481a6000; // UART3 and other

    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
    peripheralBaseAddr,
    peripheralAttrs);

    var peripheralBaseAddr = 0x47400000; // USBSS

    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
    peripheralBaseAddr,
    peripheralAttrs);

    Regards, Eric
  • Hi,

    If you using bare metal and code is similar to pdk_am335x_1_0_xx\packages\ti\starterware\, there is an API call: MMUConfigAndEnable(). It is implemented inside pdk_am335x_1_0_xx\packages\ti\starterware\examples\example_utils.

    There is a call MMUMemRegionMap(&regionDev, (uint32_t*)pageTable); you need to look at what regions are covered.

    Regards, Eric
  • Eric,
    - I'm using SYS/BIOS 6.73.1.1 with the CDC driver program, SYS/BIOS 6.53.2.0 with the non-CDC driver program.
    - CCS does not find any instances of either 'MMUConfigAndEnable' or 'MMUMemRegionMap' in the source code.
    - Both programs have a file configPkg\package\cfg\app_pea8fnv.c that gets generated somehow. Both of these files have 'FirstLevelDesc_SECTION' and ''enableMMU' but none of the other stuff that you mentioned. Even those two sections are somewhat different from what you posted. What I have is the following, which is the same in both programs.

    /* defaultAttrs__C */
    #pragma DATA_SECTION(ti_sysbios_family_arm_a8_Mmu_defaultAttrs__C, ".const:ti_sysbios_family_arm_a8_Mmu_defaultAttrs__C");
    __FAR__ const CT__ti_sysbios_family_arm_a8_Mmu_defaultAttrs ti_sysbios_family_arm_a8_Mmu_defaultAttrs__C = {
    ti_sysbios_family_arm_a8_Mmu_FirstLevelDesc_SECTION, /* type */
    0, /* bufferable */
    0, /* cacheable */
    0, /* shareable */
    0, /* noexecute */
    (xdc_UInt8)0x1, /* imp */
    (xdc_UInt8)0x0, /* domain */
    (xdc_UInt8)0x3, /* accPerm */
    (xdc_UInt8)0x1, /* tex */
    0, /* notGlobal */
    };
    ...
    /* enableMMU__C */
    #pragma DATA_SECTION(ti_sysbios_family_arm_a8_Mmu_enableMMU__C, ".const:ti_sysbios_family_arm_a8_Mmu_enableMMU__C");
    __FAR__ const CT__ti_sysbios_family_arm_a8_Mmu_enableMMU ti_sysbios_family_arm_a8_Mmu_enableMMU__C = 1;


    - There are numerous differences between the two app_pea8fnv.c files and browsing through I haven't run across anything that looks like it has to do with USB addresses. The only place where the text '4740' shows up is inside a comment in each file. No instances of the text '44E0'.

    Where to look next?

    Kevin
  • Hi,

    Issue is that you don't use any of our exist PRSDK code and things are different:

    In your CCS project map file, there should be a symbol called:

    ti.sysbios.family.arm.a8.mmuTableSection

                   0x80200000     0x4000

    *(ti.sysbios.family.arm.a8.mmuTableSection)

    ti.sysbios.family.arm.a8.mmuTableSection

                   0x80200000     0x4000 C:\ti\pdk_am335x_1_0_13\packages\MyExampleProjects\USB_DevMsc_evmAM335x_armExampleProject\Debug\configPkg\package\cfg\usb_arm_am335x_pa8fg.oa8fg

                   0x80200000                ti_sysbios_family_arm_a8_Mmu_Module_State_0_tableBuf__A

    Look at this address from CCS memory window (the beginning portion may be zero, just scroll down):

    You see there are entries like 0X40201e0e, 40301e0e,...... 0x44e00e12, ..... 0x47400e12. ....

    This is the MMU table, the 0x47400e12 is for the address 0x4740_0000 with 1MB size, you may need to check ARM doc to decode what 0xe12 means. But at least you need have such entry in your MMU. Do you see this in working case and failure case?

    Regards, Eric

  • Eric,

    The MMU tables in both cases are nearly identical. For the working (non-CDC driver) program, the only non-zero numbers are 40201E0E, 40301E0E, 48000E12, 48200E12, 80001E0E,...80601E0E. The non-working (with CDC driver) program had the exact same numbers, but also three more: 80701E0E, 80801E0E and 80901E0E which immediately followed 80001E0E,...80601E0E previously mentioned.

    I didn't see any other non-zero entries. I don't know if placement in the table is important, I didn't check that. I was just looking to see what non-zero numbers existed in the table for each program.

    Kevin
  • Kevin,

    >>>>>>>For the working (non-CDC driver) program, the only non-zero numbers are 40201E0E, 40301E0E, 48000E12, 48200E12, 80001E0E,...80601E0E. >>>>>>> Can you confirm that without MMU you can read 0x4740_0000 address in CCS or code?

    In the failure case, >>>>The non-working (with CDC driver) program had the exact same numbers, but also three more: 80701E0E, 80801E0E and 80901E0E which immediately followed 80001E0E,...80601E0E>>>>>>>>> Are you able to find out how those entries are added by your code? Then add a similar entry for 0x4740_0000 region?

    Regards, Eric
  • Digging deeper.  The mmu tables are initialized in a generated function called ti_sysbios_family_arm_a8_Mmu_initTableBuf__I which is in the file configPkg/package/cfg/app_pea8fnv.c, see below for the contents.  The text '80001E' (from the MMU entry for 0x80101e0e) also shows up in another generated files configPkg/package/cfg/app_pea8fnv.cfg.xml.  The line in this .xml file is miles long but looks like this:

    <feature name="tableBuf" type="object"><vector id='ti.sysbios.family.arm.a8.Mmu/tableBuf'  length='4096'><elem>undefined</elem><elem>undefined</elem>....<elem>0x80001e0e</elem>...

    From there is a bit murky as to what application source(s) is(are) used to generate the .c and .xml files, but I believe that XDC generates both based on at least on the application specific file called app.cfg.  Comparing the app.cfg files for the two programs does not shed any light but here are the differences:

    CDC:  execontextInstance0.memoryMap["DDR3"].len = 10485760;

    no CDC: execontextInstance0.memoryMap["DDR3"].len = 7340032;

    Both programs define two semaphores, the app.cfg entries for both are identical.  The app.cfg for the CDC program has nine additional semaphores defined that are only in the non-CDC app.cfg.  An example is the following:

    var semaphore3Params = new Semaphore.Params();
    semaphore3Params.instance.name = "semFrontIQFComplete";
    Program.global.semFrontIQFComplete = Semaphore.create(null, semaphore3Params);

    The .project file for the two programs are nearly identical, the only difference being in the <name>...</name> tag.

    There is also a am335x.cmd file which is identical for the two programs, shown below as well.  Reading 'How to Develop a Project With TI SYS/BIOS' at http://www.ti.com/lit/an/sprabw1/sprabw1.pdf, the example there seems to have a few more entries where I only have a .init section.

    To summarize...

    - It is unclear what source file(s) XDC is using to generate the MMU table since nothing in app.cfg looks like it would do that directly.

    - While the app.cfg file is different for the two programs, there does not seem to have any difference that would cause USB registers to not be available.

    - Is app.cfg supposed to have something in it that is missing from both?  If so, why does the non-CDC program work and is able to read USB registers even though the MMU table is virtually the same as the CDC program?

    Not clear where to look next.

    Kevin Jennings

    ===== Start of configPkg/package/cfg/app_pea8fnv.c contents =====

    From configPkg/package/cfg/app_pea8fnv.c for the CDC driver program

    Void ti_sysbios_family_arm_a8_Mmu_initTableBuf__I(UInt32 *mmuTableBuf)
    {
    mmuTableBuf[1026] = 0x40201e0e;
    mmuTableBuf[1027] = 0x40301e0e;
    mmuTableBuf[1152] = 0x48000e12;
    mmuTableBuf[1154] = 0x48200e12;
    mmuTableBuf[2048] = 0x80001e0e;
    mmuTableBuf[2049] = 0x80101e0e;
    mmuTableBuf[2050] = 0x80201e0e;
    mmuTableBuf[2051] = 0x80301e0e;
    mmuTableBuf[2052] = 0x80401e0e;
    mmuTableBuf[2053] = 0x80501e0e;
    mmuTableBuf[2054] = 0x80601e0e;
    mmuTableBuf[2055] = 0x80701e0e;
    mmuTableBuf[2056] = 0x80801e0e;
    mmuTableBuf[2057] = 0x80901e0e;
    }

    From configPkg/package/cfg/app_pea8fnv.c for the non-CDC driver program

    Void ti_sysbios_family_arm_a8_Mmu_initTableBuf__I(UInt32 *mmuTableBuf)
    {
    mmuTableBuf[1026] = 0x40201e0e;
    mmuTableBuf[1027] = 0x40301e0e;
    mmuTableBuf[1152] = 0x48000e12;
    mmuTableBuf[1154] = 0x48200e12;
    mmuTableBuf[2048] = 0x80001e0e;
    mmuTableBuf[2049] = 0x80101e0e;
    mmuTableBuf[2050] = 0x80201e0e;
    mmuTableBuf[2051] = 0x80301e0e;
    mmuTableBuf[2052] = 0x80401e0e;
    mmuTableBuf[2053] = 0x80501e0e;
    mmuTableBuf[2054] = 0x80601e0e;
    }

    ===== End of configPkg/package/cfg/app_pea8fnv.c contents =====

    ===== Start of app.cfg contents for program using CDC driver =====

    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    var LoggerBuf = xdc.useModule('xdc.runtime.LoggerBuf');
    var Main = xdc.useModule('xdc.runtime.Main');
    var Memory = xdc.useModule('xdc.runtime.Memory');
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    var System = xdc.useModule('xdc.runtime.System');
    var Text = xdc.useModule('xdc.runtime.Text');

    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    var Swi = xdc.useModule('ti.sysbios.knl.Swi');
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Semaphore = xdc.useModule('ti.sysbios.knl.Semaphore');
    var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');
    var Mailbox = xdc.useModule('ti.sysbios.knl.Mailbox');
    var Timestamp = xdc.useModule('xdc.runtime.Timestamp');
    var TimestampProvider = xdc.useModule('ti.sysbios.family.arm.a8.TimestampProvider');

    /*
    * Program.argSize sets the size of the .args section.
    * The examples don't use command line args so argSize is set to 0.
    */
    Program.argSize = 0x0;

    /*
    * Uncomment this line to globally disable Asserts.
    * All modules inherit the default from the 'Defaults' module. You
    * can override these defaults on a per-module basis using Module.common$.
    * Disabling Asserts will save code space and improve runtime performance.
    Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;
    */

    /*
    * Uncomment this line to keep module names from being loaded on the target.
    * The module name strings are placed in the .const section. Setting this
    * parameter to false will save space in the .const section. Error and
    * Assert messages will contain an "unknown module" prefix instead
    * of the actual module name.
    Defaults.common$.namedModule = false;
    */

    /*
    * Minimize exit handler array in System. The System module includes
    * an array of functions that are registered with System_atexit() to be
    * called by System_exit().
    */
    System.maxAtexitHandlers = 4;

    /*
    * Uncomment this line to disable the Error print function.
    * We lose error information when this is disabled since the errors are
    * not printed. Disabling the raiseHook will save some code space if
    * your app is not using System_printf() since the Error_print() function
    * calls System_printf().
    Error.raiseHook = null;
    */

    /* set errHook (defined in main.c) as the error
    * hook function. Strings begining with '&'
    * can be assigned to function pointers to
    * reference unspecified external functions
    */
    Error.raiseHook = "&errHook";

    /*
    * Uncomment this line to keep Error, Assert, and Log strings from being
    * loaded on the target. These strings are placed in the .const section.
    * Setting this parameter to false will save space in the .const section.
    * Error, Assert and Log message will print raw ids and args instead of
    * a formatted message.
    Text.isLoaded = false;
    */

    /*
    * Uncomment this line to disable the output of characters by SysMin
    * when the program exits. SysMin writes characters to a circular buffer.
    * This buffer can be viewed using the SysMin Output view in ROV.
    SysMin.flushAtExit = false;
    */

    /*
    * The BIOS module will create the default heap for the system.
    * Specify the size of this default heap.
    */
    BIOS.heapSize = 3145728;

    /* System stack size (used by ISRs and Swis) */
    Program.stack = 65536;

    /* Circular buffer size for System_printf() */
    SysMin.bufSize = 0x200;

    /*
    * Create and install logger for the whole system
    */
    var loggerBufParams = new LoggerBuf.Params();
    loggerBufParams.numEntries = 16;
    var logger0 = LoggerBuf.create(loggerBufParams);
    Defaults.common$.logger = logger0;
    Main.common$.diags_INFO = Diags.ALWAYS_ON;

    System.SupportProxy = SysMin;
    Clock.tickPeriod = 500;
    Clock.timerId = 0;
    Task.defaultStackSize = 65536;
    Hwi.dispatcherAutoNestingSupport = false;
    var execontextInstance0 = xdc.lookup('xdc.platform.ExeContext.Instance#0');
    execontextInstance0.memoryMap["DDR3"].len = 10485760;
    var semaphore0Params = new Semaphore.Params();
    semaphore0Params.instance.name = "semInitComplete";
    Program.global.semInitComplete = Semaphore.create(null, semaphore0Params);
    var semaphore1Params = new Semaphore.Params();
    semaphore1Params.instance.name = "semUSBTransferComplete";
    Program.global.semUSBTransferComplete = Semaphore.create(null, semaphore1Params);
    var semaphore2Params = new Semaphore.Params();
    semaphore2Params.instance.name = "semShutdownComplete";
    Program.global.semShutdownComplete = Semaphore.create(null, semaphore2Params);
    BIOS.cpuFreq.lo = 600000000;
    Memory.defaultHeapSize = 3145728;
    Program.sectMap["ocmc"] = new Program.SectionSpec();
    Program.sectMap["ocmc"].loadSegment = "OCMC_SRAM";
    var semaphore3Params = new Semaphore.Params();
    semaphore3Params.instance.name = "semFrontIQFComplete";
    Program.global.semFrontIQFComplete = Semaphore.create(null, semaphore3Params);
    var semaphore4Params = new Semaphore.Params();
    semaphore4Params.instance.name = "semRearIQFComplete";
    Program.global.semRearIQFComplete = Semaphore.create(null, semaphore4Params);
    var semaphore5Params = new Semaphore.Params();
    semaphore5Params.instance.name = "semFrontScaleComplete";
    Program.global.semFrontScaleComplete = Semaphore.create(null, semaphore5Params);
    var semaphore6Params = new Semaphore.Params();
    semaphore6Params.instance.name = "semRearScaleComplete";
    Program.global.semRearScaleComplete = Semaphore.create(null, semaphore6Params);
    var semaphore7Params = new Semaphore.Params();
    semaphore7Params.instance.name = "semJPEGProcessorAvailable";
    semaphore7Params.mode = Semaphore.Mode_BINARY;
    Program.global.semJPEGProcessorAvailable = Semaphore.create(1, semaphore7Params);
    var semaphore8Params = new Semaphore.Params();
    semaphore8Params.instance.name = "semOCRComplete";
    Program.global.semOCRComplete = Semaphore.create(null, semaphore8Params);
    var semaphore9Params = new Semaphore.Params();
    semaphore9Params.instance.name = "semScaleReturn";
    semaphore9Params.mode = Semaphore.Mode_BINARY;
    Program.global.semScaleReturn = Semaphore.create(null, semaphore9Params);
    var semaphore10Params = new Semaphore.Params();
    semaphore10Params.instance.name = "semScanComplete";
    Program.global.semScanComplete = Semaphore.create(null, semaphore10Params);
    var semaphore11Params = new Semaphore.Params();
    semaphore11Params.instance.name = "semImageMemoryAvailable";
    semaphore11Params.mode = Semaphore.Mode_BINARY;
    Program.global.semImageMemoryAvailable = Semaphore.create(1, semaphore11Params);

    ===== End of app.cfg contents for program using CDC driver =====

    ===== Start of am335x.cmd contents used by both programs =====

    SECTIONS
    {
    .init: { boot*(.text)} > 0x80000000 /* make sure we can boot! */
    }

    ===== End of am335x.cmd contents used by both programs =====

  • Hi,

    It is unclear how the MMU table is generated, I didn't see any entry in the app.cfg.

    1. Something you need to confirm to me:
    For the working (non-CDC driver) program, the only non-zero numbers are 40201E0E, 40301E0E, 48000E12, 48200E12, 80001E0E,...80601E0E. >>>>>>> Can you confirm that without MMU you can read 0x4740_0000 address in CCS or code?

    2. Something you can try:
    In the failure case, after load your application, the program should go main() and halt. Then you can look at the MMU table inside the CCS memory window, please manually poke the memory to add an entry for 0x4740_0000 region with value 0x47400e12. Then read from CCS memory window for this 0x47400000 region, is still ?????

    Regards, Eric
  • Eric,

    For #1, using the non-CDC program: I'm not sure what you mean by "Can you confirm that without MMU" but at the entry point to main(), 0x47400000 and 0x47401460 both show up as ???????? in the memory browser. The MMU table is at 0x80458000. The first thing in main is a call to a function MMUInit(). After returning from that function, 0x47400000 and 0x47401460 are still unchanged, unreadable. If I then let the program continue on and break at the point where the code is going to read from 0x47401460, both 0x47400000 and 0x47401460 (and everything in between) are now readable in the memory browser. Rechecking the MMU table at that point does not show any changes.

    For #2, using the CDC program: At the entry point to main(), 0x47400000 and 0x47401460 both show up as ???????? in the memory browser. The MMU table is at 0x80870000. I entered 0x47400E12 at address 0x80870010 (not sure if the exact location in the table mattered so I put it near the beginning) . After that change, reading from 0x47400000 and 0x47401460 is still unchanged, unreadable. Again, the first thing in main is a call to a function MMuInit(). After returning from that function, 0x47400000 and 0x47401460 are still unchanged, unreadable. The MMU table is still intact, I still have 0x47400E12 at address 0x80870010 there do not appear to be any other changes. If I then let the program continue on and break at the point where the code is going to attempt to read from 0x47401460, MMU table still appears unchanged, 0x47400000 and 0x47401460 are still unchanged, unreadable.

    The MmuInit function is the same in both programs, shown below.

    It would appear that there must be a call to something in the non-CDC USB device driver that changes whether the MMU blocks 0x47400000 or not but it does so in a way that doesn't affect what appears to be a static MMU table.

    Kevin Jennings

    ===== Start of MmuInit =====
    static void MmuInit(void)
    {
    unsigned int index;

    for (index = 0; index < (4*1024); index++) {
    /* Set the cache-able memory attributes */
    if ((index >= 0x800 && index < 0x840) || // DDR
    (index == 0x403) || // OCMC
    (index == 0x402)) // SRAM
    {
    pageTable[index] = (index << 20) | CACHEABLE_TLB_ATTR;
    }

    /* Set the non-cacheable memory attributes */
    else {
    pageTable[index] = (index << 20) | NORM_TLB_ATTR;
    }
    }

    /* Invalidate the TLB entries */
    CP15TlbInvalidate();

    CP15DomainAccessClientSet();

    /* Set TTB0 value. We use only TTB0 here (N = 0) */
    CP15Ttb0Set(((unsigned int )pageTable) | RGN_L2_WBWA);

    /* Enables MMU */
    CP15MMUEnable();

    /* Enable Data Cache */
    CP15DCacheEnable();

    /* Disable Instruction Cache*/
    CP15ICacheEnable();
    }
    ===== End of MmuInit =====
  • lding said:
    This is the MMU table, the 0x47400e12 is for the address 0x4740_0000 with 1MB size, you may need to check ARM doc to decode what 0xe12 means. But at least you need have such entry in your MMU. Do you see this in working case and failure case?

    CCS has utilities to decode the MMU table.

    E.g. using CCS 9.0.1 to debug the USB_DevMsc_evmAM335x_armExampleProject, with the Cortex-A8 halted, there is the Mmu view of the RTOS Object View (ROV):

    There are also the Page Table Visibility DSS API's which can be called from the CCS Scripting Console. E.g. to show there is a one-to-one mapping between the physical and virtual addresses for 0x47401400 which is for the USB0 Core:

    js:> ptvReverseLookup 0x47401400
    Physical Address = 0x0000000047401400 --> Virtual Address = 0x0000000047401400 
    
    
    js:> ptvLookupAddress 0x47401400
    Virtual Address = 0x0000000047401400 --> Physical Address = 0x0000000047401400 
     = > 
        TTBR0 Base Address = 0x80200000 
        Min VA = 0x0 
        Max VA = 0xffffffff 
         = > 
            Type = L1 Section 
            Index = 0x474 
            Min VA = 0x47400000 
            Min PA = 0x47400000 
            Region Size = 0x100000 
            S = 0x0 
            AP[1:0] = 0x3 
            nG = 0x0 
            AP[2] = 0x0 
            NS = 0x0 
            TEX[2:0] = 0x0 
            XN = 0x1 
            Domain[3:0] = 0x0 

  • Kevin Jennings said:
    It would appear that there must be a call to something in the non-CDC USB device driver that changes whether the MMU blocks 0x47400000 or not but it does so in a way that doesn't affect what appears to be a static MMU table.

    Looking at the ti-processor-sdk-rtos-am335x-evm-05.01.00.11/pdk_am335x_1_0_12/packages/ti/drv/usb/example/bios/am335x/usb_arm_am335x.cfg example configuration there is the following section which adds a MMU entry for the USBSS (amongst other peripherals used by the example):

    Mmu.enableMMU = true;
    
    // Force peripheral section to be NON cacheable strongly-ordered memory
    var peripheralAttrs = {
        type : Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
        tex: 0,
        bufferable : false,                // bufferable
        cacheable  : false,                // cacheable
        shareable  : false,                // shareable
        noexecute  : true,                 // not executable
    };
    
    // Define the base address of the 1 Meg page
    // the peripheral resides in.
    var peripheralBaseAddr = 0x44e00400;
    
    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
                              peripheralBaseAddr,
                              peripheralAttrs);
    
                              
    // Define the base address of the 1 Meg page
    // the peripheral resides in.
    var peripheralBaseAddr = 0x481a6000;	// UART3 and other
    
    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
                              peripheralBaseAddr,
                              peripheralAttrs);                          
    
    var peripheralBaseAddr = 0x47400000;	// USBSS
    
    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setFirstLevelDescMeta(peripheralBaseAddr,
                              peripheralBaseAddr,
                              peripheralAttrs);                          
    

    Can you try adding such a MMU mapping to the .cfg file for your project?

  • Chester,

    When I add the entire section of app.cfg code you posted, the build fails. The offending line in question is "Mmu.enableMMU = true;"

    (C:/SourceSafe/SmartSourceElite/Pro2_0TestProject/SmartSourceElitePro2_0/app.cfg#105)
    "./package/cfg/app_pea8fnv.cfg", line 195
    gmake.exe: *** [package/cfg/app_pea8fnv.xdl] Error 1
    js: "C:/ti/xdctools_3_50_04_43_core/packages/xdc/tools/Cmdr.xs", line 52: Error: xdc.tools.configuro: configuration failed due to earlier errors (status = 2); 'linker.cmd' deleted.
    gmake[1]: *** [build-1655140127-inproc] Error 1
    gmake[1]: Leaving directory 'C:/SourceSafe/SmartSourceElite/Pro2_0TestProject/SmartSourceElitePro2_0/Release'
    gmake: *** No rule to make target 'build-1655140127', needed by 'configPkg/compiler.opt'. Stop.

    Looking at the structure of app.cfg, it would appear that I would first have to include some form of 'xdc.useModule' command first in order to then be able to use the variable that gets returned. For example, my app.cfg sets a variable 'Memory' like this:
    var Memory = xdc.useModule('xdc.runtime.Memory');
    Then use 'Memory' like this:
    Memory.defaultHeapSize = 3145728;
    Looking at the SYS/BIOS documentation, there doesn't appear to be any other XDC module which would return anything similar to your 'Mmu' so it is unclear what further can be done along this front. PDK and SYS/BIOS are too different.

    Kevin Jennings

  • Eric,

    RTOS Object View did not show anything like the display that you posted. When I click on 'Mmu', it displays the following error message
    Error: Cannot read property "modState" from undefined
    When I click on other modules, I get different types of error messages.
    ---------------
    In the scripting console window, in response to the command "ptvReverseLookup 0x47401400" is the following:
    js:> ptvLookupAddress 0x47401400
    Virtual Address = 0x0000000047401400 --> Physical Address = Not mapped
    = >
    TTBR0 Base Address = 0x80458000
    Min VA = 0x0
    Max VA = 0xffffffff
    = >
    Type = Invalid
    Index = 0x474
    Min VA = 0x0


    js:>
    ----
    However, going back to my comment in my last post that there must be something in the 'non-CDC' program that enables access to 0x47400000 without doing anything with the MMU table, I did find something. The code that is reading from 0x47471460 appears to be in a different task than the one that the USB driver is in. As part of bringing up the USB driver in both programs, a call is made to USB0ModuleClkConfig() in file usb.cpp. When using the non-CDC driver, this call is happening before the first call to the procedure that reads from 0x47401460 but in the CDC driver the call to USB0ModuleClkConfig() happens after the procedure tries to read from 0x47401460. It is upon return from USB0ModuleClkConfig() that the USB registers like 0x47401460 become accessible and readable. I'm not able to step through the code for USB0ModuleClkConfig() to see at what specific point the USB registers become accessible, but the function is fairly short, I've posted it below.

    So it wasn't so much a difference between what the CDC driver and the non-CDC driver were doing as it was a question of when they were doing it. This also gives me what I believe will be a solution to this problem. Before reading from 0x47401460, first check to see that the USB0ModuleClkConfig() procedure has been run. If it has, do the read and return the result. If not, then report back that no USB is currently connected.

    Kevin Jennings

    ----- Start of USB0ModuleClkConfig -----
    void USB0ModuleClkConfig(void)
    {
    HWREG(SOC_CM_WKUP_REGS + CM_WKUP_CM_CLKDCOLDO_DPLL_PER) |=
    (CM_WKUP_CM_CLKDCOLDO_DPLL_PER_DPLL_CLKDCOLDO_GATE_CTRL |
    CM_WKUP_CM_CLKDCOLDO_DPLL_PER_ST_DPLL_CLKDCOLDO);


    HWREG(SOC_PRCM_REGS + CM_PER_USB0_CLKCTRL) |=
    CM_PER_USB0_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_PRCM_REGS + CM_PER_USB0_CLKCTRL) &
    CM_PER_USB0_CLKCTRL_MODULEMODE) != CM_PER_USB0_CLKCTRL_MODULEMODE_ENABLE);


    /*
    ** Waiting for IDLEST field in CM_PER_USB0_CLKCTRL register to attain the
    ** desired value.
    */
    while((CM_PER_USB0_CLKCTRL_IDLEST_FUNC <<
    CM_PER_USB0_CLKCTRL_IDLEST_SHIFT)!=
    (HWREG(SOC_CM_PER_REGS + CM_PER_USB0_CLKCTRL) &
    CM_PER_USB0_CLKCTRL_IDLEST));

    }
    ----- End of USB0ModuleClkConfig -----
  • Hi,

    >>>>This also gives me what I believe will be a solution to this problem. Before reading from 0x47401460, first check to see that the USB0ModuleClkConfig() procedure has been run. >>>> I hope you have the solution and worked.

    Regards, Eric
  • Kevin Jennings said:
    Looking at the structure of app.cfg, it would appear that I would first have to include some form of 'xdc.useModule' command first in order to then be able to use the variable that gets returned.

    I didn't post the complete Mmu setup code for the .cfg file. The missing line was:

    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');

    Kevin Jennings said:
    The code that is reading from 0x47471460 appears to be in a different task than the one that the USB driver is in. As part of bringing up the USB driver in both programs, a call is made to USB0ModuleClkConfig() in file usb.cpp. When using the non-CDC driver, this call is happening before the first call to the procedure that reads from 0x47401460 but in the CDC driver the call to USB0ModuleClkConfig() happens after the procedure tries to read from 0x47401460. It is upon return from USB0ModuleClkConfig() that the USB registers like 0x47401460 become accessible and readable.

    OK, I now realise you are using the USB CDC driver from the obsoleted STARTERWARE-SITARA.

    The AM335x peripherals are not readable if their clock is not enabled, so your change to call USB0ModuleClkConfig() before attempting to read from 0x47401460 is correct.

    I.e. doesn't appear to be a problem with the MMU setup.

  • Just confirming that insuring that the call to USB0ModuleClkConfig() precedes accessing any of the USB registers does indeed fix the problem.  All solutions look obvious in hindsight.

    Kevin Jennings