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.

Something wrong with Interaction between SYS/BIOS and interrupts

Other Parts Discussed in Thread: AM3352, SYSBIOS, AM3358

I used i2cAccelerometer.c (AM335X_StarterWare_02_00_01_01\examples\evmAM335x\accelerometer) as the basis of a some test code to test out the I2C devices on a new board design. 

It works if I change the code to poll (no interrupts). If I get the I2C interrupt it gets an exception in the HWI code when switching to the ISR stack. Note, I do not have HWI enabled in my .cfg file I have SYS/BIOS, task, timer, error handling. I tried enabling the HWI and that did not work either (same result). 

That being said, this may or may not be related. If I try to enable the Console Uart or call BIOS_Start I get a similar behavior. 

I am wondering what is missing in my configuration. I quite comfortable with the ARM and used the SYS/BIOS before but there must be something I am missing with the new GUI and SYS/BIOS version.

Right now I have a simple power on self test going and then we will start up the tasking.  

Aaron

  • Hi Aaron,

    What version of SYS/BIOS are you using?

    Also It'll be helpful if I can see what you're doing in your cfg file.

    Thanks,

    Moses

  • Moses,

    We are an AM3352. SYS/BIOS 6.35.1.29. XDCtools 3.25.0.48. Attached is the latest cfg file. I am sure it is something silly I used SYS/BIOS for years quite a while ago and something now is hidden from me.

    Aaron

    4643.app.cfg

  • Any new insight? 

    Aaron

  • Aaron.

    I have some more questions to help my understanding of the issue here. Are you trying to directly setup the I2C interrupt using Starterware and when it fires, you get an exception in the Hwi code? In your cfg file, I didn't see any Hwi instance created for the I2C peripheral, are you calling Hwi_create somewhere in your C code?

    Moses

  • Moses,

    I was not trying to use Hwi, hence it is not in my cfg. I was trying to use the native interrupt.

    Below is the code. I would like to know what the recommended way to get this to work with the native interrupt and the HWI.

    Regardless the " BIOS_start();" without any other code (i2C or otherwise) give me the same error.

    Aaron

    /*
    ** Configures i2c bus frequency and slave address.
    ** It also enable the clock for i2c module and
    ** does pinmuxing for the i2c.
    */
    void SetupI2C(void)
    {

    /* Enable IRQ in CPSR */
    #if INTERRUPT_DRIVEN
    IntMasterIRQEnable();
    #endif

    /* Configures AINTC to generate interrupt */
    I2CAintcConfigure();

    I2C0ModuleClkConfig();

    I2CPinMuxSetup(0);

    /* Put i2c in reset/disabled state */
    I2CMasterDisable(SOC_I2C_0_REGS);

    /* Auto Idle functionality is dsabled */
    I2CAutoIdleDisable(SOC_I2C_0_REGS);

    /* Configure i2c bus speed to 100khz */
    I2CMasterInitExpClk(SOC_I2C_0_REGS, I2C_SYSTEM_CLOCK, I2C_INTERNAL_CLOCK,
    I2C_OUTPUT_CLOCK);

    /* Bring I2C module out of reset */
    I2CMasterEnable(SOC_I2C_0_REGS);
    }

    /* Configures AINTC to generate interrupt */
    static void I2CAintcConfigure(void)
    {
    #if INTERRUPT_DRIVEN
    IntAINTCInit();

    /* Registering the Interrupt Service Routine(ISR). */
    IntRegister(SYS_INT_I2C0INT, I2CIsr);

    /* Setting the priority for the system interrupt in AINTC. */
    IntPrioritySet(SYS_INT_I2C0INT, 0, AINTC_HOSTINT_ROUTE_IRQ );

    /* Enabling the system interrupt in AINTC. */
    IntSystemEnable(SYS_INT_I2C0INT);
    #endif
    }

  • Aaron, 

    I see you have the code to setup the I2C interrupt which has nothing to do with SYS/BIOS but to get it to fire and be handled, you need to register it with the kernel Hwi dispatcher. In your cfg file, you can create a Hwi Instance by giving it the interrupt number of that I2C peripheral and registering your ISR function that will run every time there is an interrupt. I can walk you through how to do this.

    What do you think?

    Moses

  • Moses,

    Thank you,

    Please run me through that configuration. Is this configuration required for SYS/BIOS also to start?

    Aaron

  • Aaron,

    If your having problems getting BIOS to start, I'd suggest you start with a simple BIOS example project for your device and carefully migrate the code for the I2C acclerometer to it. Under TI Resource Explorer in CCS, you can import the "Typical" Example under the AM3352 device. This will be a good place to start. 

    Note: I'm trying to simplify the problem here, I took a look at your cfg file and there is a lot going on. I see networking and a whole lot of modules included that I don't believe you need to get the I2C accelerometer example to work.

    Let me know if you want to go this route. I'll guide you as you go along.

    So, download the Typical example, get it to build and get it to run on your device, that's step 1.

    Moses

  • Moses,

    I created a new CCS project "typical". I used the "Typical" SYS/BIOS template (example).

    I setup the Variant to AM33X - Cortex A8 and AM3353 [Cortex M]

    On the RTSC Config Screen I use the following settings Target "ti.targets.arm.elf.M3" & Platform "ti.platforms.stellaris:AM3352" Build-profile "debug".

    Then I get an error...

    Description Resource Path Location Type
    Unsupported device! .xdchelp /typical 458 C/C++ Problem

    If I double click on the error it is in Settings.xs (c:\ti\bios_6_35_01_29\packages\ti\sysbios\family\arm\Settings.xs) line 458.

    Aaron

  • Aaron,

    So AM335X devices have a Cortex A8 core (main processor) and a Cortex M3 (used for power I believe). You should have the Cortex A8 device selected and not the Cortex M like you have. The new project window should look like this:

    Let me know if you get this working

    Moses

  • Moses,

    Some progress...

    The typical worked now, with your changes by gel file and fix up the debugger settings.

    So, I took the app.cfg into my design got everything to compile and link. I removed all the network stuff (that is future work).

    However, after taking the app.cfg into my design and and just trying the BIOS_start it did not work (same crash).

    What other piece of this equation am I missing? Are the SYS/BIOS configs stored somewhere else also that I need to import into my project?

    Aaron

  • Moses,

    This is the whole project (sources and all) after I brought over the app.cfg I removed all of our proprietary stuff.

    1157.ti_simplified.zip

    I suspect I am some how structuring things in some way that is causing it not to work. I think all the logic is correct but I have run in conflict with the structure that the tools want.

    This is starting to become critical.

    Aaron

  • Aaron,

    Thanks for sending me your source. It makes it easier for me. I'm leaving the office now, so I took a quick glance at your code. The first issue I can spot is that you have your Task setup code after BIOS_start(). When you call BIOS_start(), control is passed onto the OS and it doesn't return to main therefore it should be the last statement in your main function. 

    When BIOS_starts, it will run any Task instance that you have created or if there is none, it will stay in the Idle task (created by default). So you want to have your Task setup code before BIOS_start(). Also the BIOS_exit(0) code is not needed in main. It should be called from a thread when you are sure you don't need the OS services, and BIOS_exit(), exits the program.

    I'll give you more feedback tomorrow. Implement those changes and let me know how it goes.

    Moses

  • Moses,

    I found out why BIOS_Start blows up...

    I knew what I was doing was correct but did not seem to make sense. 

    I called CP15MMUDisable (); to disable the MMU. I guess that SYS/BIOS requires the MMU.

    If I call CP15MMUEnable (); prior to BIOS_Start then it no longer dies (starts Idle task...).

    That is good news. Note, that requirement is not documented (and may even be a bug).

     

    But, since I am bringing up a board I really don't want the MMU in the way. I want to be able to open up access to ALL the registers including (I2C, UARTs, etc). Like I did in my EnableTheWorld() function without having exceptions.

    Where is the best place to open the ranges like the gel file (but in C).

    This was in the gel file.

    OnTargetConnect()
    {
    GEL_MapOff();
    GEL_MapReset();
    GEL_MapAddStr(0x00020000, 0, 0x20000000, "R", 0); // Boot ROM
    GEL_MapAddStr(0x40000000, 0, 0x0002C000, "R", 0); // Boot ROM (also at 0x20000)
    GEL_MapAddStr(0x402F0400, 0, 0x0000FC00, "R|W", 0); // SRAM Internal
    GEL_MapAddStr(0x40300000, 0, 0x00010000, "R|W", 0); // OCMC-RAM
    GEL_MapAddStr(0x44000000, 0, 0x00400000, "R|W", 0); // L3F CFG Regs
    GEL_MapAddStr(0x44800000, 0, 0x00400000, "R|W", 0); // L3S CFG Regs
    GEL_MapAddStr(0x44C00000, 0, 0x00400000, "R|W", 0); // L4_WKUP
    GEL_MapAddStr(0x46000000, 0, 0x00400000, "R|W", 0); // McASP0 Data
    GEL_MapAddStr(0x46400000, 0, 0x00400000, "R|W", 0); // McASP1 Data
    GEL_MapAddStr(0x47400000, 0, 0x00005000, "R|W", 0); // USB0/1
    GEL_MapAddStr(0x47810000, 0, 0x00010000, "R|W", 0); // MMCHS2
    GEL_MapAddStr(0x48000000, 0, 0x01000000, "R|W", 0); // L4 PER
    GEL_MapAddStr(0x49000000, 0, 0x00B00000, "R|W", 0); // EDMA
    GEL_MapAddStr(0x4A000000, 0, 0x01000000, "R|W", 0); // L4_FAST
    GEL_MapAddStr(0x4C000000, 0, 0x01000000, "R|W", 0); // EMIF
    GEL_MapAddStr(0x50000000, 0, 0x01000000, "R|W", 0); // GPMC Regs
    GEL_MapAddStr(0x56000000, 0, 0x01000000, "R|W", 0); // SGX530
    GEL_MapAddStr(0x80000000, 0, 0x40000000, "R|W", 0); // 256MB DDR3 external memory
    GEL_MapOn();
    AM335xStartState();
    AM3358_SK_Initialization();
    Disable_Watchdog();

    }

    Thanks at least some of the mystery is solved,

    Aaron

     

  • Moses,

    I tried taking a whack at this I added the following code instead of disabling the MMU (taken from one of the TI examples)... See below. i wanted to open up the entire ARM register set and RAM and OCM.

    It crashed in MMUInit because the pageTable which was passed in as R0 got clobbered in the beginning of MUEInit (from StarterWare). Why is the example code doing that?

    I will investigate more tomorrow but, would like some TI suggestions on this one since the BIOS and HWIs clearly seem to demand the MMU and the example code for the MMU crashes.

    Aaron

    #define START_ADDR_DDR (0x80000000)
    #define START_ADDR_DEV (0x44000000)
    #define START_ADDR_OCMC (0x40300000)
    #define NUM_SECTIONS_DDR (512)
    #define NUM_SECTIONS_DEV (960)
    #define NUM_SECTIONS_OCMC (1)

    static volatile unsigned int pageTable[4*1024] __attribute__((aligned(16*1024)));

    void MMUConfigAndEnable(void)
    {
        /*
        ** Define DDR memory region of AM335x. DDR can be configured as Normal
        ** memory with R/W access in user/privileged modes. The cache attributes
        ** specified here are,
        ** Inner - Write through, No Write Allocate
        ** Outer - Write Back, Write Allocate
        */
        REGION regionDdr = {
                            MMU_PGTYPE_SECTION, START_ADDR_DDR, NUM_SECTIONS_DDR,
                            MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WT_NOWA,
                                                         MMU_CACHE_WB_WA),
                            MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
                            (unsigned int*)pageTable
                           };
        /*
        ** Define OCMC RAM region of AM335x. Same Attributes of DDR region given.
        */
        REGION regionOcmc = {
                             MMU_PGTYPE_SECTION, START_ADDR_OCMC, NUM_SECTIONS_OCMC,
                             MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WT_NOWA,
                                                          MMU_CACHE_WB_WA),
                             MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
                             (unsigned int*)pageTable
                            };
        /*
        ** Define Device Memory Region. The region between OCMC and DDR is
        ** configured as device memory, with R/W access in user/privileged modes.
        ** Also, the region is marked 'Execute Never'.
        */
        REGION regionDev = {
                            MMU_PGTYPE_SECTION, START_ADDR_DEV, NUM_SECTIONS_DEV,
                            MMU_MEMTYPE_DEVICE_SHAREABLE,
                            MMU_REGION_NON_SECURE,
                            MMU_AP_PRV_RW_USR_RW  | MMU_SECTION_EXEC_NEVER,
                            (unsigned int*)pageTable
                           };
        /* Initialize the page table and MMU */
        MMUInit((unsigned int*)pageTable);
        /* Map the defined regions */
        MMUMemRegionMap(&regionDdr);
        MMUMemRegionMap(&regionOcmc);
        MMUMemRegionMap(&regionDev);
        /* Now Safe to enable MMU */
        MMUEnable((unsigned int*)pageTable);
    }
  • Moses,

    This is becoming a quagmire...

    If the MMU is enabled prior to calling MMUConfigAndEnable() then it crashes in MMUInit because R0 (masterPt) gets corrupted when CP15TlbInvalidate is called.

    So, I tried disabling the MMU in MMUConfigAndEnable via  CP15MMUDisable just prior to the call MMUInit. However, that goes off the rails even to the point that I can not get control from the debugger.

    I want your help and will gladly post a solution we we resolve this. There has to be people doing similar board bring ups who what SYSBIOS and want the MMU out of hair but want caching of DDR. 

    Aaron

  • So let me summarize what we have found and what is still an open issues...

    • SYS/BIOS only seems to work if MMU is on. This is not clear in the documentation. Also, if it is needed it should turn it on. So, now I turn it on. 
    • I want to get to all the internal peripherals so, I need to go into each of the registers and need the MMU to allow it. So, I use one of the examples that claims to all for this from the starterware code (MMUConfigAndEnable - multiple examples). That code has the opposite problem it demands the MMU be turned off when it starts. So, I turn in the beginning of MMUConfigAndEnable but then when it tries to enable the MMU then it crashes. (regardless of I enable or disable caching)
    • My simple requirement should be common to people either doing new board bring up or those who want to interface with allot of the HW on a design.
      • I need it the caching on all the DDR 
      • Access to ALL the internal peripherals of the AM3352
      • Access to all internal rams.
    • There should be a working example of this.
    • I want to know how to get the MMU to allow caching but get out of the way on everything else.

    I know you are trying to help. But, this is going slowly and there is something missing (or buried too deep in you documentation). I don't know what timezone you are in but I would like to move this along a little faster. Any suggestions would be appreciated. I would be open to a phone call.

    Aaron

  • Hi Aaron,

    When using SYS/BIOS the expectation is that the user would use BIOS APIs for MMU management. I looked at the project you shared earlier and it seems that the MMU code in the project (MMUConfigAndEnable, etc.) is conflicting with the MMU setup that BIOS does. I would recommend you to stop using Starterware APIs for MMU management and replace them with BIOS APIs.

    Here's a link to the SYS/BIOS MMU cdoc that has some example code showing how to configure the A8 MMU using BIOS APIs: http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/sysbios/6_37_01_24/exports/bios_6_37_01_24/docs/cdoc/ti/sysbios/family/arm/a8/Mmu.html#xdoc-desc

    I also have some recommended changes in the "main.c" file you shared.


    /* * ======== main ======== */ void main() { Task_Handle periodic_task_handle; Task_Params taskParams; periodic_task_handle = periodic_task_handle; System_printf("Hello\n"); // CP15MMUDisable (); -> Not required EnableTheWorld(); #if 0 quick_post(); // this talks to the I2C #endif // BIOS_start(); -> BIOS_start() never returns. Any code after this call will never run. This call should be moved below the Task_create code. Task_Params_init(&taskParams); taskParams.priority = 10; taskParams.stackSize = 0x1000; periodic_task_handle = Task_create (periodic_task, &taskParams, NULL); System_flush(); BIOS_start(); // Adding BIOS start BIOS_exit(0); /* Calling BIOS_exit(0) here has no affect as the control will never return from BIOS_start() */ }

    As a general rule you have to be careful when merging starterware code in a SYS/BIOS project. SYS/BIOS manages the interrupts, timers, caches & MMU for you and therefore any starterware code that affects any of these peripherals should be replaced with equivalent SYS/BIOS APIs.


    Best,

    Ashish

  • Ashish,

    Thank you pointing me in this direction. So, I started by grabbing the example from where you pointed me to and hit what I hope is a simple road block. 

    5241.app.cfg

    On line 123 I get... 

    ti.sysbios.family.arm.a8.Mmu.FirstLevelDescAttrs#0: no property named 'tex'

    This is right from the example and I appended it to my app.cfg.

    Aaron

  • Hi Aaron,

    My bad, I pointed you to the documentation for a newer version of BIOS. Here's a link to 6.35.01.29 docs:

    http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/sysbios/6_35_01_29/exports/bios_6_35_01_29/docs/cdoc/ti/sysbios/family/arm/a8/Mmu.html#xdoc-desc

    "tex" field was added in SYS/BIOS 6.37.00 and did not exist before.

    Best,

    Ashish

  • Ashish,

    Thanks for the info. I was given some info that misled me.

    Attached is my app.cfg that enables all the key ram areas. To help anyone else who is doing similar MMU stuff.

    8468.app.cfg

    This allowed me access to the peripherals of interest and BIOS was able to start. Good News.

    That being said, is there any reason why interrupts would not work prior to BIOS_start? As you can see I have HWI enabled in my app.cfg. I wanted to run some init and power on self test prior to the tasking starting. I thought that prior to main HWI initialization is done.

    Attached is the code that I call get_adc() just prior to BIOS_start in polled mode it works but in interrupt mode it does not. 

    2746.adc_utils.c

    0131.adc_utils.h

    Aaron

  • Aaron,

    SYS/BIOS only initializes the interrrupt controller registers during startup but it does not enable IRQs until BIOS_start() is called. Therefore, if you create a Hwi (register an ISR with BIOS) and it gets posted before BIOS_start() is called, the interrupt will not get serviced until BIOS_start() is called.

    I found an issue in your adc_5F00_utils.c file. The SetupIntc() function is going to conflct with BIOS Hwi module. SYS/BIOS already does the interrupt controller initialization (init done by Hwi module startup routine). The right way to register a ADC Hwi when using BIOS is to remove the SetupIntc() call and replace it with the below code:

    #include <ti/sysbios/family/arm/a8/intcps/Hwi.h>
    
    Hwi_Params hwiParams;
    
    Hwi_Params_init(&hwiParams);
    
    hwiParams.priority = <priority val>;
    
    hwiParams.enableInt = TRUE;
    
    Hwi_create(SYS_INT_ADC_TSC_GENINT, ADCIsr, &hwiParams, NULL);

    (See http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/sysbios/6_35_01_29/exports/bios_6_35_01_29/docs/cdoc/index.html#ti/sysbios/family/arm/a8/intcps/Hwi.html for more info)

    Best,

    Ashish

  • Ashish,

    Thank you for all your help. Interrupts and SYS/BIOS are working.

    It was not clear to me that SYS/BIOS and starterware were not compatible.

    So, here is a small followup.

    Is there any reason why I can not move the MMU initialization into my C code? The app.cfg has made the build cycle take so make longer. 

    Thanks,

    Aaron

  • Aaron,

    You can move MMU init code into a C file. There are SYS/BIOS C APIs that can be called from your C code to configure the MMU table.

    Here's some example C code:

    #include <ti/sysbios/family/arm/a8/Mmu.h>
    
    Mmu_FirstLevelDescAttrs attrs;
    Mmu_initDescAttrs(&attrs);
    
    attrs.type = Mmu_FirstLevelDesc_SECTION;
    attrs.bufferable = TRUE;
    attrs.cacheable = TRUE;
    attrs.accPerm = 3;
    
    // Update the MMU entry for 0x80000000 with the new attributes.
    Mmu_setFirstLevelDesc((Ptr)0x80000000, (Ptr)0x90000000, &attrs);

    (C API doc: http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/sysbios/6_35_01_29/exports/bios_6_35_01_29/docs/cdoc/index.html#ti/sysbios/family/arm/a8/Mmu.html#set.First.Level.Desc)

    Best,

    Ashish

  • Ashish,
    If I use the app.cfg I posted earlier it works but, if I move the logic into my C code it errors (E_dataAbort) when I touch the SOC_CM_PER_REGS (0x44e00014). I must be missing an API. See C code below.
    In the app.cfg I commented out everything after the Mmu.enableMMU = true;
    Thanks,
    Aaron
    ----- C code ----
      Mmu_disable();
        // For Cortex-A8
        Mmu_FirstLevelDescAttrs attrs;
        Mmu_initDescAttrs(&attrs);
        attrs.type = Mmu_FirstLevelDesc_SECTION;
        attrs.bufferable = TRUE;
        attrs.cacheable = TRUE;
        attrs.noexecute = FALSE;
        attrs.accPerm = 3;
        Mmu_setFirstLevelDesc((void *)0x80000000, (void *)0x90000000, &attrs);
        Mmu_initDescAttrs(&attrs);
        attrs.type = Mmu_FirstLevelDesc_SECTION;
        attrs.shareable = FALSE;
        attrs.bufferable = FALSE;
        attrs.cacheable = FALSE;
        attrs.noexecute = TRUE;
        attrs.accPerm = 3;
        Mmu_setFirstLevelDesc((void *)0x44000000, (void *)0x80000000, &attrs); // also tried (0x80000000 - 1)
        Mmu_enable();
    --- This is what I want it to be equivalent to in the app.cfg (this is what is commented out so, I can test the C code) ---
        // descriptor attribute structure 
        var attrs = { 
            type: Mmu.FirstLevelDesc_SECTION,  // SECTION descriptor 
            bufferable: true,                  // bufferable 
            cacheable: true,                   // cacheable 
        }; 
     
        // Set the descriptor for each entry in the address range 
        for (var i=0x80000000; i < 0x90000000; i = i + 0x00100000) { 
            // Each 'SECTION' descriptor entry spans a 1MB address range 
            Mmu.setFirstLevelDescMeta(i, i, attrs); 
        } 
     
        // Force peripheral section to be NON cacheable strongly-ordered memory
        var peripheralAttrs = {
            type : Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
            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 = 0x44000000;
        // Set the descriptor for each entry in the address range
        for (var i=0x44000000; i < 0x80000000; i = i + 0x00100000) {
            // Each 'SECTION' descriptor entry spans a 1MB address range
            Mmu.setFirstLevelDescMeta(i, i, peripheralAttrs);
        }

  • Hi Aaron,

    Your C code is not mapping the entire address range which is causing the problem. Also, there is an issue in the way Mmu_setFirstLevelDesc() API is being used.

    Mmu_setFirstLevelDesc() API takes the starting virtual address and physical address of a 1MB address range. So, Mmu_setFirstLevelDesc((Ptr)0x80000000, (Ptr)0x90000000, &attrs) will create a MMU entry that maps virtual address 0x80000000-0x800FFFFF to physical address 0x90000000-0x900FFFFF. In your app, I believe you need to directly map 0x80000000-0x8FFFFFFF to 0x80000000-0x8FFFFFFF as well as directly map 0x44000000-0x7FFFFFFF to itself.

    I have made some changes to your C code and shared it below. I think this should work:

    #include <ti/sysbios/family/arm/a8/Mmu.h>
    #include <xdc/std.h>
    
    // For Cortex-A8
    UInt32 idx;
    Mmu_FirstLevelDescAttrs attrs;
    Mmu_initDescAttrs(&attrs);
    attrs.type = Mmu_FirstLevelDesc_SECTION;
    attrs.bufferable = TRUE;
    attrs.cacheable = TRUE;
    attrs.noexecute = FALSE;
    attrs.accPerm = 3;
    for (idx = 0x80000000; idx < 0x90000000; idx += 0x100000) {
        Mmu_setFirstLevelDesc((Ptr)idx, (Ptr)idx, &attrs);
    }
    
    Mmu_initDescAttrs(&attrs);
    attrs.type = Mmu_FirstLevelDesc_SECTION;
    attrs.shareable = FALSE;
    attrs.bufferable = FALSE;
    attrs.cacheable = FALSE;
    attrs.noexecute = TRUE;
    attrs.accPerm = 3;
    for (idx = 0x44000000; idx < 0x80000000; idx += 0x100000) {
        Mmu_setFirstLevelDesc((Ptr)idx, (Ptr)idx, &attrs);
    }

    I removed the Mmu_disable/enable calls from the code as Mmu_setFirstLevelDesc disables the MMU if it is already enabled before updating the MMU tables.

    Best,

    Ashish

  • Ashish,

    Thank you again.

    When I read the API that was not clear.

    One more item...

    We have a collection of peripherals on the I2C. I created this generic I2C interface from TI's examples. But, it seems to be intermittent I suspect that now that the cache an all is working the timing of the examples may not be correct.

    Would you mine looking at this since you spotted my startware/SYSBIOS conflicts before? (see below)

    Thanks,

    Aaron

    --- i2c_utils.c----
    #include <ti/sysbios/family/arm/a8/intcps/Hwi.h>
    #include "hsi2c.h"
    #include "gpio_v2.h"
    #include "interrupt.h"
    #include "soc_AM335x.h"
    #include "consoleUtils.h"
    #include "evmAM335x.h"
    #include "delay.h"
    #include "i2c_utils.h"
    #define  I2C_SYSTEM_CLOCK              48000000
    #define  I2C_INTERNAL_CLOCK            12000000
    #define  I2C_OUTPUT_CLOCK              100000
    #define  I2C_CLEAR_ALL_INTERRUPTS      0x7FF
    static volatile unsigned char dataFromSlave[12];
    static volatile unsigned char dataToSlave[12];
    static volatile unsigned int numOfBytes;
    static volatile unsigned int flag = 1;
    static volatile unsigned int tCount;
    static volatile unsigned int rCount;
    static void I2CAintcConfigure(void);
    void cleanupInterrupts(void)
    {
        I2CMasterIntClearEx(SOC_I2C_0_REGS, I2C_CLEAR_ALL_INTERRUPTS);
    }
    /* Configures AINTC to generate interrupt */
    static void I2CAintcConfigure(void)
    {
        IntMasterIRQEnable();
        IntAINTCInit();
        Hwi_Params hwiParams;
        Hwi_Params_init(&hwiParams);
        hwiParams.priority = 1;
        hwiParams.enableInt = TRUE;
        Hwi_create(SYS_INT_I2C0INT, (ti_sysbios_interfaces_IHwi_FuncPtr)I2CIsr, &hwiParams, NULL);
    }
    /*
     ** Configures i2c bus frequency and slave address.
     ** It also enable the clock for i2c module and
     ** does pinmuxing for the i2c.
     */
    void SetupI2C(void)
    {
        /* Enable IRQ in CPSR */
    IntMasterIRQEnable();
        /* Configures AINTC to generate interrupt */
        I2CAintcConfigure();
    I2C0ModuleClkConfig();
        I2CPinMuxSetup(0);
        /* Put i2c in reset/disabled state */
        I2CMasterDisable(SOC_I2C_0_REGS);
        /* Auto Idle functionality is disabled */
        I2CAutoIdleDisable(SOC_I2C_0_REGS);
        /* Configure i2c bus speed to 100khz */
        I2CMasterInitExpClk(SOC_I2C_0_REGS, I2C_SYSTEM_CLOCK, I2C_INTERNAL_CLOCK,
                            I2C_OUTPUT_CLOCK);
        /* Bring I2C module out of reset */
        I2CMasterEnable(SOC_I2C_0_REGS);
    }
    /*
    ** Transmits data over I2C bus
    */
    void i2cWrite(unsigned char i2c_address, unsigned char *data, unsigned int dcount)
    {
    tCount = 0;
        /* Set i2c slave address */
        I2CMasterSlaveAddrSet(SOC_I2C_0_REGS, i2c_address);
        memcpy( (void *)&dataToSlave, (void *)data, dcount);
        /* Data Count specifies the number of bytes to be transmitted */
        I2CSetDataCount(SOC_I2C_0_REGS, dcount);
        numOfBytes = I2CDataCountGet(SOC_I2C_0_REGS);
        /* Configure I2C controller in Master Transmitter mode */
        I2CMasterControl(SOC_I2C_0_REGS, I2C_CFG_MST_TX | I2C_CFG_STOP);
        /* Transmit and Stop condition interrupt is enabled */
        I2CMasterIntEnableEx(SOC_I2C_0_REGS, I2C_INT_TRANSMIT_READY |
                                             I2C_INT_STOP_CONDITION );
        /* Generate Start Condition over I2C bus */
        I2CMasterStart(SOC_I2C_0_REGS);
        while (flag);
        flag = 1;
        /* Wait until I2C registers are ready to access */
        while(!(I2CMasterIntRawStatus(SOC_I2C_0_REGS) & (I2C_INT_ADRR_READY_ACESS)));
    }
    void i2cWriteByte(unsigned char i2c_address, unsigned char i2c_reg,
             unsigned char byte)
    {
    unsigned char txdata[2];
        txdata[0] = i2c_reg; // register
        txdata[1] = byte;
        i2cWrite(
        i2c_address,
        txdata,
                sizeof(txdata));
    }
    /*
    ** Receives data over I2C bus
    */
    void i2cRead(unsigned char i2c_address, unsigned char *wdata, unsigned int wdcount,
        unsigned char *rdata, unsigned int rdcount)
    {
    rCount = 0;
    tCount = 0;
        /* Set i2c slave address */
        I2CMasterSlaveAddrSet(SOC_I2C_0_REGS, i2c_address);
        memcpy( (void *)&dataToSlave, (void *)wdata, wdcount);
        /* Data Count specifies the number of bytes to be transmitted */
        I2CSetDataCount(SOC_I2C_0_REGS, wdcount);
        numOfBytes = I2CDataCountGet(SOC_I2C_0_REGS);
        /* Configure I2C controller in Master Transmitter mode */
        I2CMasterControl(SOC_I2C_0_REGS, I2C_CFG_MST_TX);
        /* Transmit and Stop condition interrupt is enabled */
        I2CMasterIntEnableEx(SOC_I2C_0_REGS, I2C_INT_TRANSMIT_READY);
        /* Generate Start Condition over I2C bus */
        I2CMasterStart(SOC_I2C_0_REGS);
        while (tCount != numOfBytes);
        flag = 1;
        /* Wait until I2C registers are ready to access */
        while(!(I2CMasterIntRawStatus(SOC_I2C_0_REGS) & (I2C_INT_ADRR_READY_ACESS)));
        /* Data Count specifies the number of bytes to be received */
        I2CSetDataCount(SOC_I2C_0_REGS, rdcount);
        numOfBytes = I2CDataCountGet(SOC_I2C_0_REGS);
        cleanupInterrupts();
        /* Configure I2C controller in Master Receiver mode */
        I2CMasterControl(SOC_I2C_0_REGS, I2C_CFG_MST_RX);
        /* Receive and Stop Condition Interrupts are enabled */
        I2CMasterIntEnableEx(SOC_I2C_0_REGS,  I2C_INT_RECV_READY |
                                              I2C_INT_STOP_CONDITION);
        /* Generate Start Condition over I2C bus */
        I2CMasterStart(SOC_I2C_0_REGS);
        while(I2CMasterBusBusy(SOC_I2C_0_REGS) == 0);
        while (flag);
        flag = 1;
        memcpy((void *)rdata, (void *)&dataFromSlave[0], rdcount);
    }
    unsigned char i2cReadByte(unsigned char i2c_address, unsigned char i2c_reg)
    {
    unsigned char rx_wdata[1];
    unsigned char rx_rdata[1];
    rx_wdata[0] = i2c_reg; // register
        i2cRead(
            i2c_address,
            rx_wdata,
            sizeof(rx_wdata),
            rx_rdata,
            1
        );
        return rx_rdata[0];
    }
    /*
    ** I2C Interrupt Service Routine. This function will read and write
    ** data through I2C bus.
    */
    void I2CIsr(void)
    {
        unsigned int status = 0;
        status = I2CMasterIntStatus(SOC_I2C_0_REGS);
        I2CMasterIntClearEx(SOC_I2C_0_REGS,
                       (status & ~(I2C_INT_RECV_READY | I2C_INT_TRANSMIT_READY)));
        if(status & I2C_INT_RECV_READY)
        {
             /* Receive data from data receive register */
             dataFromSlave[rCount++] = I2CMasterDataGet(SOC_I2C_0_REGS);
        I2CMasterIntClearEx(SOC_I2C_0_REGS,  I2C_INT_RECV_READY);
             if(rCount == numOfBytes)
             {
                  I2CMasterIntDisableEx(SOC_I2C_0_REGS, I2C_INT_RECV_READY);
                  /* Generate a STOP */
                  I2CMasterStop(SOC_I2C_0_REGS);
             }
        }
        if (status & I2C_INT_TRANSMIT_READY)
        {
             /* Put data to data transmit register of i2c */
            I2CMasterDataPut(SOC_I2C_0_REGS, dataToSlave[tCount++]);
            I2CMasterIntClearEx(SOC_I2C_0_REGS, I2C_INT_TRANSMIT_READY);
             if(tCount == numOfBytes)
             {
            I2CMasterIntDisableEx(SOC_I2C_0_REGS, I2C_INT_TRANSMIT_READY);
             }
        }
        if (status & I2C_INT_STOP_CONDITION)
        {
          /* Disable transmit data ready and receive data read interupt */
             I2CMasterIntDisableEx(SOC_I2C_0_REGS, I2C_INT_TRANSMIT_READY |
                                                   I2C_INT_RECV_READY     |
                          I2C_INT_STOP_CONDITION);
             flag = 0;
        }
        if(status & I2C_INT_NO_ACK)
        {
             I2CMasterIntDisableEx(SOC_I2C_0_REGS, I2C_INT_TRANSMIT_READY  |
                                                   I2C_INT_RECV_READY      |
                                                   I2C_INT_NO_ACK          |
                                                   I2C_INT_STOP_CONDITION);
             /* Generate a STOP */
             I2CMasterStop(SOC_I2C_0_REGS);
             flag = 0;
        }
    }
    int i2c_write(unsigned char slave_addr,
                         unsigned char reg_addr,
                         unsigned char length,
                         unsigned char const *data)
    {
    unsigned char temp_data[16];
    temp_data[0] = reg_addr;
    memcpy(&temp_data[1], data, length);
    i2cWrite(slave_addr, temp_data, length+1);
        return 0;
    }
    int i2c_read(unsigned char slave_addr,
                        unsigned char reg_addr,
                        unsigned char length,
                        unsigned char *data)
    {
    unsigned char temp_wdata[16];
    temp_wdata[0] = reg_addr;
    i2cRead(slave_addr, temp_wdata, 1, data, length);
        return 0;
    }
  • I realized I forgot to include what I see...

    I seems like the I2CRead I get an interrupt lost. But, if I step though the code it seems to work.

    Aaron

  • Hi Aaron,

    A few possible conflicts between BIOS and starterware that I see in the C code are as follows:

     - I2CAintcConfigure() function is calling IntAINTCInit(). I am not very familiar with starterware but it looks like starterware is going to try to initialize the ARM interrupt controller which is bad. Also, IntMasterIRQEnable() should be removed.

     - In SetupI2C() again there is a IntMasterIRQEnable() call should be removed.

    I cannot comment on the correctness of the code as I am not familiar with starterware I2C APIs.

    Best,

    Ashish

  • Ashish,

    I think the implementation of the I2C APIs and example in starterware has several timing dependencies.

    That being said is the a recommended method of talking to I2C0 via SYSBIOS then. So, I don't have the mixed interface (starterware and SYSBIOS).

    Thanks,

    Aaron

     

  • Aaron,

    the APIs Ashish was cautioning you about directly interact directly with SYS/BIOS's interrupt controller management; hence you should use the Hwi APIs to avoid unpredicted behaviors.

    SYS/BIOS doesn't have a direct API to communicate with I2C. TI-RTOS 1.21 has a I2C driver, however not for the I2C controller on the AM335x. I would encourage you to examine the I2C driver's code, as it uses TivaWare APIs to access the peripheral registers (which follows StarterWare's model). While the API signatures (and the peripheral) between TivaWare and StarterWare may differ, you can still examine on how the ISRs and RTOS primitives are implemented and utilized. I think this might save you some headaches in the long run.