uSDHC MMC Write: BWEN Never sets

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

uSDHC MMC Write: BWEN Never sets

Jump to solution
2,052 Views
elijahbrown
Contributor III

I'm trying to write a bare metal driver for the iMX6 uSDHC peripheral.  It's wired up to an eMMC device.  I'm able to initialize the emmc device and read blocks successfully.  But when I try to do a write block command (CMD24 or CMD25), the BWEN bit in the PRES_STATE register never gets set so the driver is never able to proceed on with writing data to the DATA_BUF_ACC_PORT register. 
I am using the polled mode, no interrupts or DMA.  The read operation is doing the same thing except polling the BREN bit to determine when it can read data, and this method is working fine.  I've been through all the INT_STATUS_EN register settings, BWRSEN and BRRSEN are both set.

From the datasheet: "A change of this bit from 0 to 1 occurs when the buffer can hold valid data greater than the write watermark level and the Buffer Write Ready interrupt is generated and enabled."

I'm sure the buffer write ready interrupt is being enabled, and nothing has been written to the buffer register yet so why is the bit not setting?  I have the watermark level set at 0x40 (half the FIFO).  Can you see anything I'm missing? 

Labels (1)
0 Kudos
1 Solution
1,432 Views
elijahbrown
Contributor III

Just to follow up I did get it working, but I abandoned PIO mode and modified my driver to use DMA instead.  The only slight catch was flushing and invalidating the cache, as I have dcache and l2 cache turned on.  Both caches mush be invalidated when doing a data read, and before issuing the data write cmd the dcache must be flushed followed by the l2 cache. 

View solution in original post

0 Kudos
8 Replies
1,432 Views
Yuri
NXP Employee
NXP Employee

Hello,

  Have You tried uSDHC example from the i.MX6 Platform SDK ?

(Chapter 35 [Configuring the uSDHC Driver] in “iMX6_Firmware_Guide.pdf”

describes driver details. )

https://www.freescale.com/webapp/Download?colCode=i.MX6_PLATFORM_SDK&location=null&fpsp=1&WT_TYPE=So...


Have a great day,
Yuri

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,432 Views
elijahbrown
Contributor III

Yes, I have referenced that but the problem is in the function "host_data_write":

/* Write data from src_ptr */
loop = length / (4 * wml);
for (idx = 0; idx < loop; idx++) {
    /* Wait until write available */
    while (!(HW_USDHC_PRES_STATE(instance).B.BWEN)) {
        ;
    }

    /* Write to FIFO watermark words */
    for (itr = 0; itr < wml; itr++) {
        HW_USDHC_DATA_BUFF_ACC_PORT(instance).U = *src_ptr;
        src_ptr++;
    }
}

You see it's waiting for BWEN to be set before it starts writing words into the FIFO.  This bit never sets and the code is just stuck there forever.  If I ignore the bit and just start writing, it works but you risk overflowing the FIFO then.  Any more ideas? 

0 Kudos
1,432 Views
Yuri
NXP Employee
NXP Employee

Hello,

  According to section 67.4.1 (Data Buffer) of the i.MX6 DQ Reference Manual :

“CPU polling mode:

* For a host read operation, when the number of words received in the buffer

meets or exceeds the RD_WML watermark value, by polling the BRR bit, the

Host Driver can read the Buffer Data Port register to fetch the amount of words

set in the RD_WML register from the buffer. The write operation is similar.”

   This means, as stated in section 67.4.1.1 (Write Operation Sequence) :

“When the internal DMA is not used, (the DMAEN bit in the Transfer Type register is not

set when the command is sent), the uSDHC asserts a DMA request when the amount of

buffer space exceeds the value set in the WR_WML register, and is ready for receiving

new data. At the same time, the uSDHC sets the BWR bit. The buffer write ready

interrupt will be generated if it is enabled by software.”

So, please use the BWR bit before FIFO filling.

   Also, ”the uSDHC will not start data transmission until the number of words set in
the WR_WML register can be held in the buffer. If the buffer is empty and the Host System
does not write data in time, the uSDHC will stop the CLK to avoid the data buffer underrun

situation.”

Regards,

Yuri.

1,432 Views
elijahbrown
Contributor III

Did you actually try this?  As I said in the original post, I try to do exactly this and the BWR bit never sets.  If you spin waiting for it to set, it'll spin forever.  That is the heart of the problem, the bit just never sets.  It *should* be set as there is room in the FIFO below the WML.  But it never sets.  Tried all sorts of weird stuff and it simply never sets.  Ignore it and write to the FIFO anyway and the data shows up on the eMMC device.  But then you have no way of knowing when the FIFO is full...

0 Kudos
1,432 Views
qiang_li-mpu_se
NXP Employee
NXP Employee

Hi Elijah, for your issue I think you hasn't set the SDHC correctly for non-DMA mode access, you can reference to attached code for PIO mode operation on SDHC.

1,433 Views
elijahbrown
Contributor III

Just to follow up I did get it working, but I abandoned PIO mode and modified my driver to use DMA instead.  The only slight catch was flushing and invalidating the cache, as I have dcache and l2 cache turned on.  Both caches mush be invalidated when doing a data read, and before issuing the data write cmd the dcache must be flushed followed by the l2 cache. 

0 Kudos
1,432 Views
karina_valencia
NXP Apps Support
NXP Apps Support

YuriMuhin_ng​ can you help to continue with the follow up?

0 Kudos
1,432 Views
elijahbrown
Contributor III

Let me also add that if I ignore BWEN and just start writing data to the DATA_BUF_ACC_PORT register, it gets clocked out to the eMMC device and is stored correctly.  I can read it back and it's there, basically everything works.  The only problem with this is when writing multiple blocks you don't have any way to know when the hardware FIFO is getting full. 

I've tried writing the FIFO at full CPU speed and at each write to DATA_BUF_ACC_PORT checking BWEN to see if it ever goes high, but it never does.  No transition, nothing.  Just always zero.  The FIFO clearly gets overrun though.  How is this even supposed to work?  It seems like this bit is just dead, and yet all the example code I've seen thus far uses it...

0 Kudos