From 429891d106713cdf4d7f770176ad82006665df69 Mon Sep 17 00:00:00 2001 From: Raymond Lei Date: Tue, 17 Dec 2024 16:07:54 -0600 Subject: [PATCH] drivers: sai: the 1st frame synchronization signal lost in slave side According the RM document, RT1170 58.3.3 (should be same for other MCU which has a similiar SAI IP): "A valid frame sync is also ignored (slave mode) or not generated (master mode) for the first four bit clock cycles after enabling the transmitter or receiver." but in fact, we found master side send out a valid frame sync at the 3rd bit clock cycles which cause this frame sync is ignored by the slave side and frame data lost. To workaround this issue, bit clock is enabled before TE/RE. Signed-off-by: Raymond Lei --- mcux/mcux-sdk/drivers/sai/fsl_sai.c | 32 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/mcux/mcux-sdk/drivers/sai/fsl_sai.c b/mcux/mcux-sdk/drivers/sai/fsl_sai.c index ece8ea2bd..6fbff2a3d 100644 --- a/mcux/mcux-sdk/drivers/sai/fsl_sai.c +++ b/mcux/mcux-sdk/drivers/sai/fsl_sai.c @@ -509,8 +509,15 @@ void SAI_TxEnable(I2S_Type *base, bool enable) /* If clock is sync with Rx, should enable RE bit. */ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) == 0x1U) { + base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_BCE_MASK); base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK); } + /* Sometimes, bit clock starts just 3 clocks before frame synchronization + * signal, which cause the 1st frame sync is ignored by the RX side as + * described in RT1170 RM 58.3.3. To make bit clock at least 4 clocks earlier, + * here, we enable bit clock firstly. + */ + base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_BCE_MASK); base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK); /* Also need to clear the FIFO error flag before start */ SAI_TxClearStatusFlags(base, kSAI_FIFOErrorFlag); @@ -520,8 +527,10 @@ void SAI_TxEnable(I2S_Type *base, bool enable) /* If Rx not in sync with Tx, then disable Tx, otherwise, shall not disable Tx */ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) != 0x1U) { - /* Disable TE bit */ - base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~I2S_TCSR_TE_MASK)); + /* Disable TE bit. Bit clock will not be disabled by disabling TE bit, we need + * disable it at the same time. + */ + base->TCSR = ((base->TCSR & 0xFFE3FFFFU) & (~(I2S_TCSR_TE_MASK | I2S_TCSR_BCE_MASK))); } } } @@ -539,8 +548,15 @@ void SAI_RxEnable(I2S_Type *base, bool enable) /* If clock is sync with Tx, should enable TE bit. */ if (((base->RCR2 & I2S_RCR2_SYNC_MASK) >> I2S_RCR2_SYNC_SHIFT) == 0x1U) { + base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_BCE_MASK); base->TCSR = ((base->TCSR & 0xFFE3FFFFU) | I2S_TCSR_TE_MASK); } + /* Sometimes, bit clock starts just 3 clocks before frame synchronization + * signal, which cause the 1st frame sync is ignored by the RX side as + * described in RT1170 RM 58.3.3. To make bit clock at least 4 clocks earlier, + * here, we enable bit clock firstly. + */ + base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_BCE_MASK); base->RCSR = ((base->RCSR & 0xFFE3FFFFU) | I2S_RCSR_RE_MASK); /* Also need to clear the FIFO error flag before start */ SAI_RxClearStatusFlags(base, kSAI_FIFOErrorFlag); @@ -550,8 +566,10 @@ void SAI_RxEnable(I2S_Type *base, bool enable) /* If Tx not in sync with Rx, then disable Rx, otherwise, shall not disable Rx */ if (((base->TCR2 & I2S_TCR2_SYNC_MASK) >> I2S_TCR2_SYNC_SHIFT) != 0x1U) { - /* Disable RE bit */ - base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~I2S_RCSR_RE_MASK)); + /* Disable RE bit. Bit clock will not be disabled by disabling RE bit, we need + * disable it at the same time. + */ + base->RCSR = ((base->RCSR & 0xFFE3FFFFU) & (~(I2S_RCSR_RE_MASK | I2S_RCSR_BCE_MASK))); } } } @@ -851,7 +869,8 @@ void SAI_TxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai } else { - tcr2 &= ~(I2S_TCR2_BCD_MASK); + /* Clear BCP bit before set it. */ + tcr2 &= ~(I2S_TCR2_BCD_MASK | I2S_TCR2_BCP_MASK); tcr2 |= I2S_TCR2_BCP(config->bclkPolarity); } @@ -879,7 +898,8 @@ void SAI_RxSetBitclockConfig(I2S_Type *base, sai_master_slave_t masterSlave, sai } else { - rcr2 &= ~(I2S_RCR2_BCD_MASK); + /* Clear BCP bit before set it. */ + rcr2 &= ~(I2S_RCR2_BCD_MASK | I2S_RCR2_BCP_MASK); rcr2 |= I2S_RCR2_BCP(config->bclkPolarity); }