Hello,
I'm currently developping a baremetal application using GPMI. The functions read_raw and write_raw, read_page and some others are working. Now I want to develop the write_page function but I doesn't work properly. I've ge GPMI bch interrupt rising but nothing appends on the data of the NAND. Can someone have a look to my function ? :
int8_t GPMI_WritePage(uint32_t p_PageNumber, uint8_t * p_Buffer)
{
dmaCmd_t l_DescCle1Address, l_DescCle2;
dmaCmd_t l_DescWaitForReady1Wait, l_DescWaitForReady1Sense;
dmaCmd_t l_DescWaitForReady2Wait, l_DescWaitForReady2Sense;
dmaCmd_t l_DescTerminatorSuccess, l_DescTerminatorFail;
dmaCmd_t l_DescCommandAddress, l_DescReadResult;
dmaCmd_t l_DescWriteData;
uint8_t l_cle1AddressBuffer[1+MAX_ROWS+MAX_COLUMNS] __attribute__((aligned(4)));
uint8_t l_cle2Buffer __attribute__((aligned(4)));
uint8_t l_commandAddressBuffer[2] __attribute__((aligned(4)));
uint8_t l_StatusResult __attribute__((aligned(4)));
uint8_t oob[64] = {0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
portBaseType xWasRunningPrivileged;
g_IsDmaInterruptNeeded = false;
l_cle2Buffer = NandCommandCode_WritePage;
l_cle1AddressBuffer[0] = NandCommandCode_SerialDataInput;
l_cle1AddressBuffer[1] = 0;
l_cle1AddressBuffer[2] = 0;
l_cle1AddressBuffer[3] = p_PageNumber & 0xff;
l_cle1AddressBuffer[4] = (p_PageNumber >> & 0xFF;
l_cle1AddressBuffer[5] = (p_PageNumber >> 16) & 0xFF;
l_DescCle1Address.data = (BF_APBH_CHn_CMD_XFER_COUNT(6)
| BF_APBH_CHn_CMD_CMDWORDS(3)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(1)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_READ));
l_DescCle1Address.address = (uint32_t)&l_cle1AddressBuffer;
// Need to set CLE high, then send command, then clear CLE, set ALE high
// send # address bytes (Column then row).
// Address increment is only enabled if there is at least one address byte.
l_DescCle1Address.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_LOCK_CS(1)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_CLE)
| BF_GPMI_CTRL0_ADDRESS_INCREMENT(BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED)
| BF_GPMI_CTRL0_XFER_COUNT(6));
l_DescCle1Address.pio_words[1] = 0;
l_DescCle1Address.pio_words[2] = 0;
l_DescCle1Address.next = &l_DescWriteData;
// nxt pointer is not set here
l_DescWriteData.data = BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER) | BF_APBH_CHn_CMD_CHAIN(1) |
BF_APBH_CHn_CMD_WAIT4ENDCMD(1) | BF_APBH_CHn_CMD_SEMAPHORE(1) | BF_APBH_CHn_CMD_CMDWORDS(6);
l_DescWriteData.address = 0;
l_DescWriteData.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA));
l_DescWriteData.pio_words[1] = 0;
l_DescWriteData.pio_words[2] = (BV_FLD(GPMI_ECCCTRL, ENABLE_ECC, ENABLE) |
BV_FLD(GPMI_ECCCTRL, ECC_CMD, ENCODE) |
BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE);
l_DescWriteData.pio_words[3] = 2048 + 64 ;
l_DescWriteData.pio_words[4] = (uint32_t)p_Buffer;
l_DescWriteData.pio_words[5] = (uint32_t)oob;
l_DescWriteData.next = &l_DescCle2;
l_DescCle2.address = (uint32_t)&l_cle2Buffer;
// Need to set CLE high, then send command, then clear CLE, set ALE high
// send # address bytes (Column then row).
// Address increment is only enabled if there is at least one address byte.
l_DescCle2.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_LOCK_CS(1)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_CLE)
| BF_GPMI_CTRL0_ADDRESS_INCREMENT(0)
| BF_GPMI_CTRL0_XFER_COUNT(1));
l_DescCle2.pio_words[1] = 0;
l_DescCle2.pio_words[2] = 0;
l_DescCle2.next = &l_DescWaitForReady1Wait;
// First we want to wait for Ready. Set GPMI wait for ready.
l_DescWaitForReady1Wait.next = &l_DescWaitForReady1Sense;
l_DescWaitForReady1Wait.data = (BF_APBH_CHn_CMD_CMDWORDS(1)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_NANDWAIT4READY(1)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
l_DescWaitForReady1Wait.address = 0;
l_DescWaitForReady1Wait.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WAIT_FOR_READY)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA)
| BF_GPMI_CTRL0_CS(NAND_CS));
l_DescWaitForReady1Sense.data = (BF_APBH_CHn_CMD_CMDWORDS(0)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_SENSE));
l_DescWaitForReady1Sense.address = (uint32_t)&l_DescTerminatorFail;
l_DescWaitForReady1Sense.pio_words[0] = 0;
l_DescWaitForReady1Sense.next = &l_DescTerminatorSuccess;
// No next descriptor in the chain.
l_DescTerminatorSuccess.next = &l_commandAddressBuffer;
l_DescTerminatorFail.next = NULL;
// Decrement semaphore, set IRQ, no DMA transfer.
l_DescTerminatorSuccess.data = (BF_APBH_CHn_CMD_IRQONCMPLT(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(0) //1) XXX changed on MX6
| BF_APBH_CHn_CMD_SEMAPHORE(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
// The failure descriptor uses exactly the same DMA command as success.
l_DescTerminatorFail.data = l_DescTerminatorSuccess.data;
// The bar holds the result code, either success or an error code. It is up to
// the DMA handling code to read the result code out of the APBH register.
l_DescTerminatorSuccess.address = (void *)SUCCESS;
l_DescTerminatorFail.address = (void *)FAIL;
l_commandAddressBuffer[0] = NandCommandCode_ReadStatus;
l_commandAddressBuffer[1] = 0x00;
l_DescWaitForReady2Wait.next = &l_DescWaitForReady1Sense;
l_DescWaitForReady2Wait.data = (BF_APBH_CHn_CMD_CMDWORDS(1)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_NANDWAIT4READY(1)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
l_DescWaitForReady2Wait.address = 0;
l_DescWaitForReady2Wait.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WAIT_FOR_READY)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA)
| BF_GPMI_CTRL0_CS(NAND_CS));
l_DescWaitForReady2Sense.data = (BF_APBH_CHn_CMD_CMDWORDS(0)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_SENSE));
l_DescWaitForReady2Sense.address = (uint32_t)&l_DescTerminatorFail;
l_DescWaitForReady2Sense.pio_words[0] = 0;
l_DescWaitForReady2Sense.next = &l_DescCommandAddress;
// tx_dma.nxt = 0;
l_DescCommandAddress.data = (BF_APBH_CHn_CMD_XFER_COUNT(1)
| BF_APBH_CHn_CMD_CMDWORDS(3)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(1)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_READ));
l_DescCommandAddress.address = (uint32_t)&l_commandAddressBuffer;
// Need to set CLE high, then send command, then clear CLE, set ALE high
// send # address bytes (Column then row).
// Address increment is only enabled if there is at least one address byte.
l_DescCommandAddress.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, WRITE)
| BF_GPMI_CTRL0_WORD_LENGTH(BV_GPMI_CTRL0_WORD_LENGTH__8_BIT)
| BF_GPMI_CTRL0_LOCK_CS(1)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_CLE)
| BF_GPMI_CTRL0_ADDRESS_INCREMENT(0)
| BF_GPMI_CTRL0_XFER_COUNT(1));
l_DescCommandAddress.pio_words[1] = 0;
l_DescCommandAddress.pio_words[2] = 0;
l_DescCommandAddress.next = &l_DescReadResult;
l_DescReadResult.data = (BF_APBH_CHn_CMD_XFER_COUNT( NAND_READ_ID_RESULT_SIZE )
| BF_APBH_CHn_CMD_CMDWORDS(1)
| BF_APBH_CHn_CMD_HALTONTERMINATE(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(1)
| BF_APBH_CHn_CMD_SEMAPHORE(0)
| BF_APBH_CHn_CMD_NANDLOCK(0)
| BF_APBH_CHn_CMD_CHAIN(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, DMA_WRITE));
// Save Data into buffer.
assert((((uint32_t)l_StatusResult) & 0x3) == 0);
l_DescReadResult.address = (uint32_t)&l_StatusResult;
// Setup GPMI for 8-bit read.
l_DescReadResult.pio_words[0] = (BV_FLD(GPMI_CTRL0, COMMAND_MODE, READ)
| BV_FLD(GPMI_CTRL0, WORD_LENGTH, 8_BIT)
| BF_GPMI_CTRL0_CS(NAND_CS)
| BF_GPMI_CTRL0_LOCK_CS(0)
| BV_FLD(GPMI_CTRL0, ADDRESS, NAND_DATA)
| BF_GPMI_CTRL0_XFER_COUNT(NAND_READ_STATUS_RESULT_SIZE));
l_DescReadResult.next = &l_DescTerminatorSuccess;
// No next descriptor in the chain.
l_DescTerminatorSuccess.next = NULL;
l_DescTerminatorFail.next = NULL;
// Decrement semaphore, set IRQ, no DMA transfer.
l_DescTerminatorSuccess.data = (BF_APBH_CHn_CMD_IRQONCMPLT(1)
| BF_APBH_CHn_CMD_WAIT4ENDCMD(0) //1) XXX changed on MX6
| BF_APBH_CHn_CMD_SEMAPHORE(1)
| BV_FLD(APBH_CHn_CMD, COMMAND, NO_DMA_XFER));
// The failure descriptor uses exactly the same DMA command as success.
l_DescTerminatorFail.data = l_DescTerminatorSuccess.data;
// The bar holds the result code, either success or an error code. It is up to
// the DMA handling code to read the result code out of the APBH register.
l_DescTerminatorSuccess.address = (void *)SUCCESS;
l_DescTerminatorFail.address = (void *)FAIL;
xWasRunningPrivileged = xPortRaisePrivilege();
vMmuArmLevel1DataCacheCleanAndInvalidate();
vMmuArmLevel2DataCacheCleanAndInvalidate();
portRESTORE_PRIVILEGE( xWasRunningPrivileged );
DMA_Run(&l_DescCle1Address);
return (l_StatusResult & 1) == 0 ? SUCCESS : -1;
}
Best regards