Skip to content

Commit

Permalink
sdmmc: I/O phase adjustments
Browse files Browse the repository at this point in the history
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 #8521
Related to #8257
igrr authored and Icarus113 committed Apr 14, 2023
1 parent ad46b43 commit e9badf5
Showing 4 changed files with 21 additions and 23 deletions.
35 changes: 17 additions & 18 deletions components/driver/sdmmc/sdmmc_host.c
Original file line number Diff line number Diff line change
@@ -116,33 +116,29 @@ esp_err_t sdmmc_host_reset(void)
static void sdmmc_host_set_clk_div(int div)
{
// Set frequency to 160MHz / div
// div = p + 1
// duty cycle = (h + 1)/(p + 1) (should be = 1/2)
// div = l + 1
// duty cycle = (h + 1)/(l + 1) (should be = 1/2)
assert (div > 1 && div <= 16);
int p = div - 1;
int l = div - 1;
int h = div / 2 - 1;

SDMMC.clock.div_factor_p = p;
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
#if SOC_SDMMC_SUPPORT_XTAL_CLOCK
SDMMC.clock.clk_sel = 1;
#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;
// Wait for the clock to propagate
esp_rom_delay_us(10);
/* 90 deg. delay for cclk_out to satisfy large hold time for SDR12 (up to 25MHz) and SDR25 (up to 50MHz) modes.
* 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)
@@ -300,7 +296,7 @@ esp_err_t sdmmc_host_get_real_freq(int slot, int* real_freq_khz)
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;
*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) {
return ESP_ERR_INVALID_STATE;
}
/* Outputs should be synchronized to cclk_out */
cmd.use_hold_reg = 1;

int64_t t0 = esp_timer_get_time();
while (SDMMC.cmd.start_command == 1) {
if (esp_timer_get_time() - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) {
1 change: 0 additions & 1 deletion components/driver/sdmmc/sdmmc_transaction.c
Original file line number Diff line number Diff line change
@@ -305,7 +305,6 @@ static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd)
if (cmd->flags & SCF_RSP_CRC) {
res.check_response_crc = 1;
}
res.use_hold_reg = 1;
if (cmd->data) {
res.data_expected = 1;
if ((cmd->flags & SCF_CMD_READ) == 0) {
4 changes: 2 additions & 2 deletions components/soc/esp32/include/soc/sdmmc_struct.h
Original file line number Diff line number Diff line change
@@ -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_din: 3; ///< phase of data input clock
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_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 val;
4 changes: 2 additions & 2 deletions components/soc/esp32s3/include/soc/sdmmc_struct.h
Original file line number Diff line number Diff line change
@@ -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_din: 3; ///< phase of data input clock
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_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 clk_sel : 1; ///< clock source select (0: XTAL, 1: 160 MHz from PLL)
uint32_t reserved24: 8;

0 comments on commit e9badf5

Please sign in to comment.