sdmmc: I/O phase adjustments

1. Fix incorrect meaning of SDMMC.clock bits, synchronize the names
   with the TRM.
2. Choose input and output phases to satisfy typical timing
   requirements.
3. Move use_hold_reg setting into the host driver, since it is related
   to timing.

Closes https://github.com/espressif/esp-idf/issues/8521
Related to https://github.com/espressif/esp-idf/issues/8257
This commit is contained in:
Ivan Grokhotkov
2022-03-12 00:53:43 +01:00
committed by Armando
parent ad46b43c2c
commit e9badf51c7
4 changed files with 21 additions and 23 deletions

View File

@ -116,33 +116,29 @@ esp_err_t sdmmc_host_reset(void)
static void sdmmc_host_set_clk_div(int div) static void sdmmc_host_set_clk_div(int div)
{ {
// Set frequency to 160MHz / div // Set frequency to 160MHz / div
// div = p + 1 // div = l + 1
// duty cycle = (h + 1)/(p + 1) (should be = 1/2) // duty cycle = (h + 1)/(l + 1) (should be = 1/2)
assert (div > 1 && div <= 16); assert (div > 1 && div <= 16);
int p = div - 1; int l = div - 1;
int h = div / 2 - 1; int h = div / 2 - 1;
SDMMC.clock.div_factor_p = p;
SDMMC.clock.div_factor_h = h; SDMMC.clock.div_factor_h = h;
SDMMC.clock.div_factor_m = p; SDMMC.clock.div_factor_l = l;
SDMMC.clock.div_factor_n = l;
// Make sure 160 MHz source clock is used // Make sure 160 MHz source clock is used
#if SOC_SDMMC_SUPPORT_XTAL_CLOCK #if SOC_SDMMC_SUPPORT_XTAL_CLOCK
SDMMC.clock.clk_sel = 1; SDMMC.clock.clk_sel = 1;
#endif #endif
#if SOC_SDMMC_USE_GPIO_MATRIX
// 90 degree phase on input and output clocks
const int inout_clock_phase = 1;
#else
// 180 degree phase on input and output clocks
const int inout_clock_phase = 4;
#endif
// Set phases for in/out clocks
SDMMC.clock.phase_dout = inout_clock_phase;
SDMMC.clock.phase_din = inout_clock_phase;
SDMMC.clock.phase_core = 0; SDMMC.clock.phase_core = 0;
// Wait for the clock to propagate /* 90 deg. delay for cclk_out to satisfy large hold time for SDR12 (up to 25MHz) and SDR25 (up to 50MHz) modes.
esp_rom_delay_us(10); * Whether this delayed clock will be used depends on use_hold_reg bit in CMD structure,
* determined when sending out the command.
*/
SDMMC.clock.phase_dout = 1;
SDMMC.clock.phase_din = 0;
esp_rom_delay_us(1);
} }
static void sdmmc_host_input_clk_disable(void) static void sdmmc_host_input_clk_disable(void)
@ -300,7 +296,7 @@ esp_err_t sdmmc_host_get_real_freq(int slot, int* real_freq_khz)
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
int host_div = SDMMC.clock.div_factor_p + 1; int host_div = SDMMC.clock.div_factor_l + 1;
int card_div = slot == 0 ? SDMMC.clkdiv.div0 : SDMMC.clkdiv.div1; int card_div = slot == 0 ? SDMMC.clkdiv.div0 : SDMMC.clkdiv.div1;
*real_freq_khz = sdmmc_host_calc_freq(host_div, card_div); *real_freq_khz = sdmmc_host_calc_freq(host_div, card_div);
@ -317,6 +313,9 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg) {
if (cmd.data_expected && cmd.rw && (SDMMC.wrtprt.cards & BIT(slot)) != 0) { if (cmd.data_expected && cmd.rw && (SDMMC.wrtprt.cards & BIT(slot)) != 0) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
/* Outputs should be synchronized to cclk_out */
cmd.use_hold_reg = 1;
int64_t t0 = esp_timer_get_time(); int64_t t0 = esp_timer_get_time();
while (SDMMC.cmd.start_command == 1) { while (SDMMC.cmd.start_command == 1) {
if (esp_timer_get_time() - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { if (esp_timer_get_time() - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) {

View File

@ -305,7 +305,6 @@ static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd)
if (cmd->flags & SCF_RSP_CRC) { if (cmd->flags & SCF_RSP_CRC) {
res.check_response_crc = 1; res.check_response_crc = 1;
} }
res.use_hold_reg = 1;
if (cmd->data) { if (cmd->data) {
res.data_expected = 1; res.data_expected = 1;
if ((cmd->flags & SCF_CMD_READ) == 0) { if ((cmd->flags & SCF_CMD_READ) == 0) {

View File

@ -379,9 +379,9 @@ typedef volatile struct sdmmc_dev_s {
uint32_t phase_dout: 3; ///< phase of data output clock (0x0: 0, 0x1: 90, 0x4: 180, 0x6: 270) uint32_t phase_dout: 3; ///< phase of data output clock (0x0: 0, 0x1: 90, 0x4: 180, 0x6: 270)
uint32_t phase_din: 3; ///< phase of data input clock uint32_t phase_din: 3; ///< phase of data input clock
uint32_t phase_core: 3; ///< phase of the clock to SDMMC peripheral uint32_t phase_core: 3; ///< phase of the clock to SDMMC peripheral
uint32_t div_factor_p: 4; ///< controls clock period; it will be (div_factor_p + 1) / 160MHz
uint32_t div_factor_h: 4; ///< controls length of high pulse; it will be (div_factor_h + 1) / 160MHz uint32_t div_factor_h: 4; ///< controls length of high pulse; it will be (div_factor_h + 1) / 160MHz
uint32_t div_factor_m: 4; ///< should be equal to div_factor_p uint32_t div_factor_l: 4; ///< controls clock period; it will be (div_factor_l + 1) / 160MHz
uint32_t div_factor_n: 4; ///< should be equal to div_factor_l
uint32_t reserved21: 11; uint32_t reserved21: 11;
}; };
uint32_t val; uint32_t val;

View File

@ -376,9 +376,9 @@ typedef volatile struct sdmmc_dev_s {
uint32_t phase_dout: 3; ///< phase of data output clock (0x0: 0, 0x1: 90, 0x4: 180, 0x6: 270) uint32_t phase_dout: 3; ///< phase of data output clock (0x0: 0, 0x1: 90, 0x4: 180, 0x6: 270)
uint32_t phase_din: 3; ///< phase of data input clock uint32_t phase_din: 3; ///< phase of data input clock
uint32_t phase_core: 3; ///< phase of the clock to SDMMC peripheral uint32_t phase_core: 3; ///< phase of the clock to SDMMC peripheral
uint32_t div_factor_p: 4; ///< controls clock period; it will be (div_factor_p + 1) / 160MHz
uint32_t div_factor_h: 4; ///< controls length of high pulse; it will be (div_factor_h + 1) / 160MHz uint32_t div_factor_h: 4; ///< controls length of high pulse; it will be (div_factor_h + 1) / 160MHz
uint32_t div_factor_m: 4; ///< should be equal to div_factor_p uint32_t div_factor_l: 4; ///< controls clock period; it will be (div_factor_l + 1) / 160MHz
uint32_t div_factor_n: 4; ///< should be equal to div_factor_l
uint32_t reserved1 : 2; uint32_t reserved1 : 2;
uint32_t clk_sel : 1; ///< clock source select (0: XTAL, 1: 160 MHz from PLL) uint32_t clk_sel : 1; ///< clock source select (0: XTAL, 1: 160 MHz from PLL)
uint32_t reserved24: 8; uint32_t reserved24: 8;