/** * @brief Write data to NAND. * * @param[in] nandp pointer to the @p NANDDriver object * @param[in] data buffer with data to be written * @param[in] datalen size of data buffer * @param[in] addr pointer to address buffer * @param[in] addrlen length of address * @param[out] ecc pointer to store computed ECC. Ignored when NULL. * * @return The operation status reported by NAND IC (0x70 command). * * @notapi */ uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data, size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc) { nandp->state = NAND_WRITE; nand_lld_write_cmd (nandp, NAND_CMD_WRITE); osalSysLock(); nand_lld_write_addr(nandp, addr, addrlen); /* Now start DMA transfer to NAND buffer and put thread in sleep state. Tread will be woken up from ready ISR. */ nandp->state = NAND_DMA_TX; osalDbgAssert((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0, "State machine broken. ECCEN must be previously disabled."); if (NULL != ecc){ nandp->nand->PCR |= FSMC_PCR_ECCEN; } dmaStartMemCopy(nandp->dma, nandp->dmamode, data, nandp->map_data, datalen); nand_lld_suspend_thread(nandp); osalSysUnlock(); if (NULL != ecc){ while (! (nandp->nand->SR & FSMC_SR_FEMPT)) ; *ecc = nandp->nand->ECCR; nandp->nand->PCR &= ~FSMC_PCR_ECCEN; } return nand_lld_read_status(nandp); }
/** * @brief Ready interrupt handler * * @param[in] nandp pointer to the @p NANDDriver object * * @notapi */ static void nand_isr_handler (NANDDriver *nandp) { osalSysLockFromISR(); #if !STM32_NAND_USE_EXT_INT osalDbgCheck(nandp->nand->SR & FSMC_SR_IRS); /* spurious interrupt happened */ nandp->nand->SR &= ~FSMC_SR_IRS; #endif switch (nandp->state){ case NAND_READ: nandp->state = NAND_DMA_RX; dmaStartMemCopy(nandp->dma, nandp->dmamode, nandp->map_data, nandp->rxdata, nandp->datalen); /* thread will be waked up from DMA ISR */ break; case NAND_ERASE: /* NAND reports about erase finish */ nandp->state = NAND_READY; wakeup_isr(nandp); break; case NAND_PROGRAM: /* NAND reports about page programming finish */ nandp->state = NAND_READY; wakeup_isr(nandp); break; default: osalSysHalt("Unhandled case"); break; } osalSysUnlockFromISR(); }
/* * Application entry point. */ int main(void) { unsigned i; static uint8_t patterns1[4096], patterns2[4096], buf1[4096], buf2[4096]; /* System initializations. - HAL initialization, this also initializes the configured device drivers and performs the board-specific initializations. - Kernel initialization, the main() function becomes a thread and the RTOS is active.*/ halInit(); chSysInit(); /* Creates the blinker thread.*/ chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO + 10, Thread1, NULL); /* Activates the ADC1 driver and the temperature sensor.*/ adcStart(&ADCD1, NULL); adcSTM32EnableTSVREFE(); /* Starts an ADC continuous conversion and its watchdog virtual timer.*/ chVTSet(&adcvt, MS2ST(10), tmo, (void *)"ADC timeout"); adcStartConversion(&ADCD1, &adcgrpcfg2, samples2, ADC_GRP2_BUF_DEPTH); /* Activating SPI drivers.*/ spiStart(&SPID1, &hs_spicfg); spiStart(&SPID2, &hs_spicfg); spiStart(&SPID3, &hs_spicfg); /* Starting SPI threads instances.*/ chThdCreateStatic(waSPI1, sizeof(waSPI1), NORMALPRIO + 1, spi_thread, &SPID1); chThdCreateStatic(waSPI2, sizeof(waSPI2), NORMALPRIO + 1, spi_thread, &SPID2); chThdCreateStatic(waSPI3, sizeof(waSPI3), NORMALPRIO + 1, spi_thread, &SPID3); /* Allocating two DMA2 streams for memory copy operations.*/ if (dmaStreamAllocate(STM32_DMA2_STREAM6, 0, NULL, NULL)) chSysHalt("DMA already in use"); if (dmaStreamAllocate(STM32_DMA2_STREAM7, 0, NULL, NULL)) chSysHalt("DMA already in use"); for (i = 0; i < sizeof (patterns1); i++) patterns1[i] = (uint8_t)i; for (i = 0; i < sizeof (patterns2); i++) patterns2[i] = (uint8_t)(i ^ 0xAA); /* Normal main() thread activity, it does continues memory copy operations using 2 DMA streams at the lowest priority.*/ while (true) { virtual_timer_t vt; chVTObjectInit(&vt); /* Starts a VT working as watchdog to catch a malfunction in the DMA driver.*/ chVTSet(&vt, MS2ST(10), tmo, (void *)"copy timeout"); /* Copy pattern 1.*/ dmaStartMemCopy(STM32_DMA2_STREAM6, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns1, buf1, sizeof (patterns1)); dmaStartMemCopy(STM32_DMA2_STREAM7, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns1, buf2, sizeof (patterns1)); dmaWaitCompletion(STM32_DMA2_STREAM6); dmaWaitCompletion(STM32_DMA2_STREAM7); if (memcmp(patterns1, buf1, sizeof (patterns1))) chSysHalt("pattern error"); if (memcmp(patterns1, buf2, sizeof (patterns1))) chSysHalt("pattern error"); /* Copy pattern 2.*/ dmaStartMemCopy(STM32_DMA2_STREAM6, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns2, buf1, sizeof (patterns2)); dmaStartMemCopy(STM32_DMA2_STREAM7, STM32_DMA_CR_PL(0) | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE, patterns2, buf2, sizeof (patterns2)); dmaWaitCompletion(STM32_DMA2_STREAM6); dmaWaitCompletion(STM32_DMA2_STREAM7); if (memcmp(patterns2, buf1, sizeof (patterns2))) chSysHalt("pattern error"); if (memcmp(patterns2, buf2, sizeof (patterns2))) chSysHalt("pattern error"); /* Stops the watchdog.*/ chVTReset(&vt); chThdSleepMilliseconds(2); } return 0; }