Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Fixes of the SD card driver

I am using the SD card driver from nRF5 SDK v17.0.2. Device nrf52840, IDE Segger, Custom PCB. nRF52 DK as progremmer.

There are problems when deinitializing the SD card.

If initialization failed, the deinitialization procedure is called in the interrupt handler, but then the card state is assigned the value IDLE instead of UNINITIALIZED, as a result, if we call deinitialization again in our program, the program freezes, due to the fact that the state of the card is IDLE and the state of SPI is UNINITIALIZED. An attempt to re-initialize SPI will result in an error and the program will hang.

1. I have made changes and ask the experts to comment on whether I did the right thing?

I also made changes in original driver that allow the card to work on SPI3 at a frequency of 32 MHz. But it doesn't matter for the described problem.

Part of the original code from the interrupt handler, which handles command responce missing:

       if (!rx_data && m_cb.state.op != SDC_OP_RESET)
        {
            // Command response missing.
            sdc_evt_t evt;
            evt.result = SDC_ERROR_NOT_RESPONDING;
            switch (m_cb.state.op)
            {
                case SDC_OP_RESET:
                case SDC_OP_IDENTIFICATION:
                    evt.type      = SDC_EVT_INIT;
                    m_cb.state.op = SDC_OP_IDLE;
                    APP_ERROR_CHECK(app_sdc_uninit());
                    break;
                case SDC_OP_READ:
                    evt.type      = SDC_EVT_READ;
                    break;
                case SDC_OP_WRITE:
                    evt.type      = SDC_EVT_WRITE;
                    break;
                default:
                    APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
                    break;
            }

            SDC_CS_DEASSERT();
            m_cb.state.op = SDC_OP_IDLE;
            m_cb.handler(&evt);
            return;
        }

With my change:

       if (!rx_data && m_cb.state.op != SDC_OP_RESET)
        {
            // Command response missing.
            sdc_evt_t evt;
            evt.result = SDC_ERROR_NOT_RESPONDING;
            switch (m_cb.state.op)
            {
                case SDC_OP_RESET:
                case SDC_OP_IDENTIFICATION:
                    evt.type      = SDC_EVT_INIT;
                    m_cb.state.op = SDC_OP_IDLE;
                    APP_ERROR_CHECK(app_sdc_uninit());
                    SDC_CS_DEASSERT();            
                    m_cb.handler(&evt);
                    break;
                case SDC_OP_READ:
                    evt.type      = SDC_EVT_READ;
                    SDC_CS_DEASSERT();
                    m_cb.state.op = SDC_OP_IDLE;
                    m_cb.handler(&evt);
                    break;
                case SDC_OP_WRITE:
                    evt.type      = SDC_EVT_WRITE;
                    SDC_CS_DEASSERT();
                    m_cb.state.op = SDC_OP_IDLE;
                    m_cb.handler(&evt);
                    break;
                default:
                    APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
                    SDC_CS_DEASSERT();
                    m_cb.state.op = SDC_OP_IDLE;
                    m_cb.handler(&evt);
                    break;
            }

            return;
        }

  • I don't know if this might help, but I was recently looking to solve the problem of someone removing the SD card while mounted. Unmounting then Re-mounting wouldn't work for some unknown reason. What I suspected is that the SPI bus was not uniniting and so the app_sd drivers were skipping the 80 clock cycles to get it back to spi mode. I solved it by adding a app_sdc_uninit(); after the following

    ff_result = f_mount(NULL, "", 1);
    disk_state = disk_uninitialize(0);
    app_sdc_uninit();
    This is abbreviated as the checks and such are removed, but the app_sdc_uninit() resolved this so that when someone attempts a write now it remounts and initializes.
    This might just be brute forcing it but seems to work until I can figure out why disk_uninitialize(0) which should be uniniting the SPI bus isn't.
Related