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/AM5728: Conflict between MMU configuration and FATFS

Part Number: AM5728
Other Parts Discussed in Thread: SYSBIOS

Tool/software: TI-RTOS

Hello,

We're working on a project that is utilizing the System DMA to manage reading data into ping pong buffers. When one buffer is full, we'd like to be able to write that data to the SD card using FATFS. The MMU is enabled with the following configuration for the System DMA for register access during runtime:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//System DMA register ACCESS via MMU descriptor modifications
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    var Mmu     = xdc.useModule('ti.sysbios.family.arm.a15.Mmu');
    Mmu.enableMMU = true;

    // descriptor attribute structure
    var peripheralAttrs1 = new Mmu.DescriptorAttrs();

    Mmu.initDescAttrsMeta(peripheralAttrs1);

    peripheralAttrs1.type = Mmu.DescriptorType_BLOCK;  // BLOCK descriptor
    peripheralAttrs1.noExecute = true;                 // not executable
    peripheralAttrs1.accPerm = 0;                      // read/write at PL1
    peripheralAttrs1.attrIndx = 1;                     // MAIR0 Byte1 describes
                                                      // memory attributes for
                                                      // each BLOCK MMU entry

    // write memory region attribute in mairRegAttr[1] i.e. MAIR0 Reg Byte1
    Mmu.setMAIRMeta(2, 0x0);    // Mark mem regions as strongly ordered memory

    // Define the base address of the 2 MB page
    // the peripheral resides in.
    //0x4A056000//dma_system
    var peripheralBaseAddr1 = 0x4A056000;
 
    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setSecondLevelDescMeta(peripheralBaseAddr1,
                               peripheralBaseAddr1,
                               peripheralAttrs1);

And our FATFS initialization:

// MMCSD function table for MMCSD implementation
FATFS_DrvFxnTable FATFS_drvFxnTable = {
    MMCSD_close,
    MMCSD_control,
    MMCSD_init,
    MMCSD_open,
    MMCSD_write,
    MMCSD_read
};

// FATFS configuration structure
FATFS_HwAttrs FATFS_initCfg[_VOLUMES] =
{
    {
        0U
    },
    {
        1U
    },
    {
        2U
    },
    {
        3U
    }
};

// FATFS objects
FATFS_Object FATFS_objects[_VOLUMES];

// FATFS configuration structure
const FATFS_Config FATFS_config[_VOLUMES + 1] = {
    {
        &FATFS_drvFxnTable,
        &FATFS_objects[0],
        &FATFS_initCfg[0]
    },

    {
         &FATFS_drvFxnTable,
         &FATFS_objects[1],
         &FATFS_initCfg[1]
    },

    {
         &FATFS_drvFxnTable,
         &FATFS_objects[2],
         &FATFS_initCfg[2]
    },

    {NULL, NULL, NULL},

    {NULL, NULL, NULL}
};

FATFS_Handle fatfsHandle = NULL;

void initFATFS()
{
    EDMA3_DRV_Result edmaResult = 0;
    EDMA3_RM_Handle gEdmaHandle = NULL;
    MMCSD_v1_HwAttrs hwAttrsConfig;

    gEdmaHandle = (EDMA3_RM_Handle)edma3init(MMCSD_EDMACC_NUM, &edmaResult);

    if(MMCSD_socGetInitCfg(0,&hwAttrsConfig)!=0) {
       //MMCSD_log("\nUnable to obtain MMCSD config.Exiting. TEST FAILED.\r\n");
       return;
    }

    hwAttrsConfig.edmaHandle = gEdmaHandle;
    if(MMCSD_socSetInitCfg(0,&hwAttrsConfig)!=0) {
        //MMCSD_log("\nUnable to set config.Exiting. TEST FAILED.\r\n");
         return;
    }

    FATFS_init();
    FATFS_open(0U, NULL, &fatfsHandle);
}

Writing to SD card:

while(1)
    {
        Semaphore_pend(sdWrite_sem_handle, BIOS_WAIT_FOREVER);
        powerDown_FLAG = 0; // turn off power down for rest of fatfs writing
        fr = f_stat(fileName, &fno);

        while(fno.fsize > MAX_FILE_SIZE)
        {
            if(fr == FR_NO_FILE) break;

            fileCntr++;
            snprintf(fileName, sizeof(char) * 32, "%s-%i.txt", sysTimeFormatted, fileCntr); // format filename with counter
            fr = f_stat(fileName, &fno);
        }

        fr = f_open(&fil, fileName, FA_OPEN_ALWAYS | FA_WRITE);
        if (fr) return;
        f_lseek(&fil, f_size(&fil));

        if(buffer2Process == 1)
        {
            f_write(&fil, msgBuf1, sizeof(msgBuf1)-1, &bytesRead);

        }
        else if(buffer2Process == 2)
        {
            f_write(&fil, msgBuf2, sizeof(msgBuf2)-1, &bytesRead);
        }
        else
        {
            f_write(&fil, msgBuf3, sizeof(msgBuf3)-1, &bytesRead);
        }

        f_close(&fil); // Close the file
        powerDown_FLAG = 1; // turn on power down mode
    }

With this setup, as soon as it reaches the first FATFS command in the while loop, the system exits. If I remove the MMU configuration then the FATFS works properly, but our data is not collected via the system DMA. Any insights would be greatly appreciated!

Thanks,

John

  • Hi,

    The FATFS initialization code is similar to the example pdk_am57xx_1_0_x\packages\ti\drv\mmcsd\example\fatfs_console\src\mmcsd_fatfs_console.c. It looks OK. And you used the EDMA for the transfer when writing into MMCSD, if you disable EDMA for this, do you still see the issue?

    In the .cfg file, I saw you used:
    eripheralAttrs1.type = Mmu.DescriptorType_BLOCK; // BLOCK descriptor
    peripheralAttrs1.noExecute = true; // not executable
    peripheralAttrs1.accPerm = 0; // read/write at PL1
    peripheralAttrs1.attrIndx = 1; // MAIR0 Byte1 describes
    // memory attributes for
    // each BLOCK MMU entry

    // write memory region attribute in mairRegAttr[1] i.e. MAIR0 Reg Byte1
    Mmu.setMAIRMeta(2, 0x0); // Mark mem regions as strongly ordered memory

    If attrIdx is 1, why you change Mmu.setMAIRMeta(2, x). Seems this is not relevant. Also, we have a suggestion to keep MAIR0-3 use the default from CCS, but change MAIR4-7 for your usage.

    As you used the MMCSD with EDMA, please double check there is a MMU setup like:
    /* Map MMC1 regs in MMU */
    var peripheralAttrs = new Mmu.DescriptorAttrs();
    Mmu.initDescAttrsMeta(peripheralAttrs);
    peripheralAttrs.type = Mmu.DescriptorType_BLOCK; // BLOCK descriptor
    peripheralAttrs.noExecute = true; // not executable
    peripheralAttrs.accPerm = 0; // read/write at PL1
    peripheralAttrs.attrIndx = 1; // MAIR0 Byte1 describes
    // memory attributes for
    // each BLOCK MMU entry

    // Configure the corresponding MMU page descriptor accordingly
    Mmu.setSecondLevelDescMeta(0x43300000,
    0x43300000,
    peripheralAttrs);

    You can see this at pdk_am57xx_1_0_x\packages\ti\drv\mmcsd\example\fatfs_console\am572x\armv7\bios\mmcsddma_idk.cfg

    Regards, Eric
  • Hi Eric,

    Yes we still see the same issue when we tried without EDMA. I was originally missing Mmcsd.Settings.useDma = "true" in my .cfg file, but that didn't fix the issue. I'm still fairly new to embedded work so our MMU configuration was from the samples in the ccs help context. I'm not sure why we original added Mmu.setMAIRMeta(2, 0x0), but our collect from the ADC's using DMA will not work without that line. I've also learned that is what is causing the FATFS trouble as well. If I comment out Mmu.setMAIRMeta(2, 0x0) then FATFS works, but our collect doesn't. When I put it back in, the data collect works but FATFS does not.

    I tried disabling the MMU altogether which allowed both aspects to work, both our collect and the fatfs drivers. But the f_write function seems to be going fairly slow in comparison, writing a 207MB buffer in 165 seconds is around 1.2MB/s. I believe we're currently collecting data at 10MB/s.

  • John,

    Sorry for the late as I was in travel. You may take a look at the SYSBIOS A15 MMU user guide, e.g.: software-dl.ti.com/.../Mmu.html

    ARGUMENTS
    attrIndx — Select appropriate MAIR register (0 or 1) and byte offset within the selected register
    attr — Memory attribute encoding
    DETAILS
    MAIR0 and MAIR1 provide the memory attribute encodings to the possible attrIndx values in a long-descriptor format translation table entry for stage 1 translations.
    attrIndx[1:0] selects the ATTRn bit-field in the selected MAIR register.
    attrIndx[2] selects the MAIR register.
    If attrIndx[2] == 0, use MAIR0
    If attrIndx[2] == 1, use MAIR1
    Memory Attribute Indirection Register (MAIR) 0 and 1 bit assignments:
    |31 | 24|23 | 16|15 | 8|7 | 0|
    --------------------------------------------------------------
    MAIR0 | ATTR3 | ATTR2 | ATTR1 | ATTR0 |
    --------------------------------------------------------------
    MAIR1 | ATTR7 | ATTR6 | ATTR5 | ATTR4 |
    --------------------------------------------------------------
    SYS/BIOS assigns the following defaults to MAIR0 ATTR0, ATTR1 and ATTR2:
    ATTR0 -> 0x44 (mark memory region as non-cacheable normal memory)
    ATTR1 -> 0x00 (mark memory region as strongly ordered and non-cacheable)
    ATTR2 -> 0xFF (mark memory region as normal memory, RW cacheable and
    RW allocate)


    You have this setting: Mmu.setMAIRMeta(2, 0x0) for ADC and System DMA working. This uses ATTR2 with strongly ordered. You may find out in your .CFG file for MMU setup, which peripheral/memory region used attrIndx2? E.g. ADC? EDMA?

    What attrIndx you used for MMCSD region? And what the value is?

    Regards, Eric
  • Hi Eric,

    Thanks for your reply, I'm starting to slow understand how these settings work. I'm still a little confused though, I can change my System DMA register to other attrIndx values and it still works, as long as I keep Mmu.setMAIRMeta(2, 0x0). As soon as I change that, our DMA ping pong linked list does not setup properly. Here's the full MMU section we're currently using in our .cfg file:

    var Mmu     = xdc.useModule('ti.sysbios.family.arm.a15.Mmu');
    
    // Enable the MMU (Required for L1 data caching)
    Mmu.enableMMU = true;
    
    Mmu.setMAIRMeta(0, 0x44);    // Mark mem region as non-cacheable normal memory
    Mmu.setMAIRMeta(1, 0x00);    // Mark mem region as strongly ordered memory
    Mmu.setMAIRMeta(2, 0x00);    // Mark mem region as strongly ordered memory
    
    var attrs = new Mmu.DescriptorAttrs();
    Mmu.initDescAttrsMeta(attrs);
    attrs.type = Mmu.DescriptorType_BLOCK;
    attrs.noExecute = true;
    attrs.accPerm = 0;      // R/W at PL1
    
    // Set IO Delay configuration areas as non-cache 
    attrs.attrIndx = 1;		// Use MAIR0 Byte1
    Mmu.setSecondLevelDescMeta(0x4844a000, 0x4844a000, attrs);
    Mmu.setSecondLevelDescMeta(0x4ae07d00, 0x4ae07d00, attrs);
    
    // McASP register ACCESS via MMU descriptor modifications
    attrs.attrIndx = 3;     // Use MAIR0 Byte3
    Mmu.setSecondLevelDescMeta(0x48464000, 0x48464000, attrs);
    
    // System DMA register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x4A056000, 0x4A056000, attrs);
    
    // Control Module register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x4A002000, 0x4A002000, attrs);
    
    // CM_CORE__CKGEN 0x4A00 8100 register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x4A008100, 0x4A008100, attrs);
    
    // GPIO 0x4805 1000 register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x48051000, 0x48051000, attrs);
    
    // CM_CORE_AON register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x4A000000, 0x4A000000, attrs);
    
    // PRM register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x4AE00000, 0x4AE00000, attrs);
    
    //MCASP2_DAT_MAIN_L3 register ACCESS via MMU descriptor modifications
    Mmu.setSecondLevelDescMeta(0x45C00000, 0x45C00000, attrs);
    
    // EDMA_TPCC register ACCESS via MMU descriptor modifications
    //attrs.attrIndx = 5; 	 // Use MAIR1 Byte1
    //Mmu.setSecondLevelDescMeta(0x43300000, 0x43300000, attrs);

    I tried changing most of our register access items to attrIndx 3 and moved our EDMA register to attrIndx 5, but even with those settings the FATFS code still causes a system exit.

    I'm just not sure why if we're setting up our System DMA registers to attrIndx 3, why I still have to use setMAIRMeta(2, 0x0) for them to setup properly.

  • Hi,

    I saw you used AttrIndex 3 and 5, but I am not sure what their value and properties. Also, I don't know why you set MAIR1 and MAIR2 both 0, kind of duplicated. It is good to use ROV view to understand:

    1. Load your application, it should go main(). Don't run (otherwise your code crash when accessing FATFS or DMA didn't work). The SYSBIOS should setup the MMU already

    2. Use CCS ----->Tools----->ROV classic, then look at Mmu

    3. From raw, you should see the value of MAIR0 to 7, also location of first/second level MMU table

    4. From Level2View, each block is 2MB, you can see each memory region (for you it is 0x4000_0000, not 0x8000_0000, not 0xc000_0000)

    You can check if you missed any region, what index used and region property.

    Regards, Eric

  • Hi Eric,

    Thank you for the information on where to view the MMU mapping in the ROV!

    The SRAM and OCMC_RAM's were being mapped to attrIndx 2. So I took out all of our individual mapping and used the for loop method to map a large section that I found in one of the TI example projects. We also switched back to using the defaults for MAIR index 0 = 0x44, 1 = 0x04, and 2 =0xFF. The combination of these changes seemed to fix our issues. Our collection via DMA is now working along with the FATFS commands. Thank you again for the guidance through this issue!

    // descriptor attribute structure
    var attrs0 = new Mmu.DescriptorAttrs();
    
    Mmu.initDescAttrsMeta(attrs0);
    attrs0.type = Mmu.DescriptorType_BLOCK;    // BLOCK descriptor
    attrs0.shareable = 2;                      // sharerable
    attrs0.attrIndx = 1;                       // Non-cache, device memory
    attrs0.noExecute = true;                   // Not executable
    
    // Set the descriptor for each entry in the address range
    for (var i=0x40600000; i < 0x60000000; i = i + 0x00200000) {
        // Each 'BLOCK' descriptor entry spans a 2MB address range
        Mmu.setSecondLevelDescMeta(i, i, attrs0);
    }