EmbeddedRelated.com
Forums

Failing to get Keil RL-FlashFS working on ARM LPC2388 (MCB2300 board)

Started by perdrix 8 months ago5 replieslatest reply 8 months ago70 views

I have taken the sample project found in: C:\Keil_v5\ARM\Boards\Keil\MCB2300\RL\FlashFS and copied it to a work area.

The project as supplied is set up for an LPC2378, so I changed it to use an LPC2388 as this is what's fitted to my MCB2300 board.

It builds just fine, but any attempt to call finit returns a 2 (after a noticeable delay).

If I press stop in the debugger I see it is waiting on the "busy loop" in the ReadBlock function (MCI_LPC23xx.c) checking for for completion of the DMA transfer from the card.

  static BOOL ReadBlock (U32 bl, U8 *buf, U32 cnt) {
  /* Read one or more 512 byte blocks from Flash Card. */
  U32 i;

  /* Set MCI Transfer registers. */
  MCI_DATA_TMR  = DATA_RD_TOUT_VALUE;
  MCI_DATA_LEN  = cnt * 512;

  /* Start DMA Peripheral to Memory transfer. */
  DmaStart (DMA_READ, buf);
  MCI_DATA_CTRL = 0x9B;

  for (i = DMA_TOUT; i; i--) {
    if (GPDMA_RAW_INT_TCSTAT & 0x01) {
      /* Data transfer finished. */
      return (__TRUE);
    }
  }
  /* DMA Transfer timeout. */
  return (__FALSE);
}

Eventually DMA_TOUT reaches 0 and the function returns __FALSE.

I tried changing the configuration of File_Config.c to place the work buffers into the USB Address range (0x7fD00000, 0x2000) as I'd read that DMA didn't work unless the buffers were in that memory region.  Sadly that didn't solve the problem :(

Help please, thanks David

[ - ]
Reply by hodgecAugust 25, 2023

Not much to go on here.  I'll assume GPDMA_RAW_INT_TCSTAT is the GPDMA Raw Interrupt Terminal Count Status Register  Since you are using 0x01 then you are looking at channel 0. I would recommend a close review of the setup and programming of the GPDMA registers.

1. Check that you powered it.  In the PCONP register set bit PCGPDMA. Note: On reset, the GPDMA is disabled (PCGPDMA = 0).
2. Make sure you enabled the clock
3. Initialization/program the GPDMA


To program a DMA channel:
1. Choose a free DMA channel with the priority required. DMA channel 0 has the highest priority and DMA channel 1 the lowest priority. 


2. Clear any pending interrupts on the channel to be used by writing to the
DMACIntTCClr Register, DMACIntClear and DMACIntErrClr Register The previous
channel operation might have left interrupts active. 


3. Write the source address into the DMACCxSrcAddr Register and
DMACC1SrcAddr. 


4. Write the destination address into the DMACC0DestAddr and DMACC1DestAddr Registers. 


5. Write the address of the next Linked List Item (LLI) into the DMACC0LLI and DMACC1LLI Registers  If the transfer consists of a single packet of data then 0 must be written into this register. 


6. Write the control information into the DMACCxControl Register (Section 30–10.4
“Channel Control Registers (DMACC0Control - 0xFFE0 410C and DMACC0Control -
0xFFE0 412C)”). 


7. Write the channel configuration information into the DMACCxConfiguration Register. In this case DMACC0Configuration. If the Enable bit is set
then the DMA channel is automatically enabled.


You'll find all of the above information in the lpc23xx users manual:

https://www.keil.com/dd/docs/datashts/philips/lpc23xx_um.pdf


[ - ]
Reply by perdrixAugust 25, 2023

Another reply:

MCI Setup:

static BOOL Init (void) {
  /* Initialize MCI interface. */

  /* Power Up the MCI and DMA controller. */
  PCONP   |=  0x30000000;

  /* MCIPWR pin is active high. */
  /* Required for the silicon rev. 'B' and later. */
  SCS     |=        0x08;

  /* Enable MCI pins. */
  PINSEL1 &= ~0x00003FC0;
  PINSEL1 |=  0x00002A80;
  PINSEL4 &= ~0x0FC00000;
  PINSEL4 |=  0x0A800000;

  /* Clear all pending interrupts. */
  MCI_COMMAND   = 0;
  MCI_DATA_CTRL = 0;
  MCI_CLEAR     = 0x7FF;

  /* Power up, switch on VCC for the Flash Card. */
  MCI_POWER  = 0x02;
  Delay (10000);

  /* Power on the Flash Card. */
  MCI_POWER |= 0x01;

  return (__TRUE);
}        

I think that definitely powers the DMA.  And the code to send/rcv:

static void DmaStart (U32 mode, U8 *buf) {
  /* Configure DMA for read or write. */

  if (mode == DMA_READ) {
    /* Transfer from MCI-FIFO to memory. */
    GPDMA_CH0_SRC  = (U32)&MCI_FIFO;
    GPDMA_CH0_DEST = (U32)buf;
    /* The burst size set to 8, transfer size 512 bytes. */
    GPDMA_CH0_CTRL = (512 >> 2)   | (0x02 << 12) | (0x02 << 15) | 
                     (0x02 << 18) | (0x02 << 21) | (1 << 27)    | (1u << 31);
    GPDMA_CH0_CFG  = 0x10001 | (0x04 << 1) | (0x00 << 6) | (0x06 << 11);
  }
  else {
    /* Transfer from memory to MCI-FIFO. */
    GPDMA_CH0_SRC  = (U32)buf;
    GPDMA_CH0_DEST = (U32)&MCI_FIFO;
    /* The burst size set to 8, transfer size 512 bytes. */
    GPDMA_CH0_CTRL = (512 >> 2)   | (0x02 << 12) | (0x02 << 15) |
                     (0x02 << 18) | (0x02 << 21) | (1 << 26)    | (1u << 31);
    GPDMA_CH0_CFG  = 0x10001 | (0x00 << 1) | (0x04 << 6) | (0x05 << 11);
  }
  /* Enable DMA channels, little endian */
  GPDMA_INT_TCCLR = 0x01;
  GPDMA_CONFIG    = 0x01;
}

So I *think* is is setup correctly.

Cheers, Dave


[ - ]
Reply by hodgecAugust 25, 2023

I reviewed the Init() setup with the manual and agree with the values you have set.  However I believe you also need to configure the Clock Control Register (MCIClock).  Per the manual the bit 8, Clock Enable Bit, is 0 at reset.  See page 495 in the manual I provided you.


GPDMA_CH0_CTRL = (512 >> 2) | (0x02 << 12) | (0x02 << 15) |
                 (0x02 << 18) | (0x02 << 21) | (1 << 27)| (1u << 31);

I don't agree with ( 512 >> 2)  The transfer size occupies bits 11:0 so a 512 byte transfer should be (512 >> 0 ) or 512.


GPDMA_CH0_CFG  = 0x10001 | (0x00 << 1) | (0x04 << 6) | (0x05 << 11);

I believe the above is incorrect, as it does not appear to be selecting the MCI peripheral. See page 647 of the manual I provided you.

[ - ]
Reply by perdrixAugust 25, 2023

Thanks I will check that - but remember I didn't write that code - it was supplied as a sample by Keil (not saying it's necessarily correct because of that).

MCI_CLOCK is set elsewhere in this code:

static BOOL BusSpeed (U32 kbaud) {
  /* Set a MCI clock speed to desired value. */
  U32 div;

  /* baud = MCLK / (2 x (div + 1)) */
  div = (__MCLK/2000 + kbaud - 1) / kbaud;
  if (div > 0)    div--;
  if (div > 0xFF) div = 0xFF;
  MCI_CLOCK = (MCI_CLOCK & ~0xFF) | 0x300 | div;
  return (__TRUE);
}

which is called from the FlashFS library code.

I need to study the GDPMA chapter - I will update this when I have done so.


[ - ]
Reply by perdrixAugust 27, 2023

An update.  Their code wouldn't work at all with any 1GB SD card formatted as FAT (even if formatted with the SD Card Association's formatting program) - it always returned a 2 from finit("").   With a 4GB SDHC card formatted as FAT32 it was "Happy as Larry"!

That really doesn't say much for the quality of the code.  I'd forgive them if it failed on huge SDXC cards formatted as exFat, but not working on a regular SD card is pretty unforgivable.