FlexSPI IP FIFO filling very slow

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

FlexSPI IP FIFO filling very slow

1,863 次查看
matthiaspimming
Contributor I

Hi all,

we fill the IP TX FIFO with 32x4 Byte Data by IP Bus to transmit Data via FlexSPI. So, on each transfer we fill the FIFO with 128 Byte Data. Unfortunately, the filing of the FIFO is very slow. Those transfer is measured with Oscilloscope and needs about 2us.

For us it is not logical that the FIFO transfer is so slow because the IP Bus is running with 132MHz.

How can we improve the FIFO filling speed?

Is the Bottleneck the AHB to IP Bridge (AIPSTZ) clock (aips_tz3_hclk)?

I am really looking forward to your answer.

BR

0 项奖励
回复
7 回复数

1,690 次查看
matthiaspimming
Contributor I

Hi Victor,

I am using RT1051.

FASTCODE long HBWriteTransfer(register unsigned long *buffer0, unsigned long addr0)
{
   register unsigned long* fifo = (unsigned long*) &FLEXSPI->TFDR[0];
   FLEXSPI->IPCR0 = addr0;
   FLEXSPI->IPTXFCR |= 1;
   FLEXSPI->IPRXFCR |= 1;
   FLEXSPI->IPCR1 = (WRITE_SEQUENCE<<16) | 128;
   *(fifo+0) = *(buffer0+0);
   *(fifo+1) = *(buffer0+1);
   *(fifo+2) = *(buffer0+2);
   *(fifo+3) = *(buffer0+3);
   *(fifo+4) = *(buffer0+4);
   *(fifo+5) = *(buffer0+5);
   *(fifo+6) = *(buffer0+6);
   *(fifo+7) = *(buffer0+7);
   *(fifo+8) = *(buffer0+8);
   *(fifo+9) = *(buffer0+9);
   *(fifo+10) = *(buffer0+10);
   *(fifo+11) = *(buffer0+11);
   *(fifo+12) = *(buffer0+12);
   *(fifo+13) = *(buffer0+13);
   *(fifo+14) = *(buffer0+14);
   *(fifo+15) = *(buffer0+15);
   *(fifo+16) = *(buffer0+16);
   *(fifo+17) = *(buffer0+17);
   *(fifo+18) = *(buffer0+18);
   *(fifo+19) = *(buffer0+19);
   *(fifo+20) = *(buffer0+20);
   *(fifo+21) = *(buffer0+21);
   *(fifo+22) = *(buffer0+22);
   *(fifo+23) = *(buffer0+23);
   *(fifo+24) = *(buffer0+24);
   *(fifo+25) = *(buffer0+25);
   *(fifo+26) = *(buffer0+26);
   *(fifo+27) = *(buffer0+27);
   *(fifo+28) = *(buffer0+28);
   *(fifo+29) = *(buffer0+29);
   *(fifo+30) = *(buffer0+30);
   *(fifo+31) = *(buffer0+31);
   FLEXSPI->INTR |= (1<<6);
   FLEXSPI->IPCMD |= 1;
   while (!(FLEXSPI->STS0 & ((1<<1)) && (1<<0)))
   if(FLEXSPI->INTR & ((1<<1) | (1<<3))) goto PROGERROR;
   return 0;
   PROGERROR:
   FLEXSPI->INTR = 0x00000F3F;
   return -1;
}

Best Regards

0 项奖励
回复

1,690 次查看
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Matthias, 

How you are filling the FIFO it's practically the same way that we fill it on the SDK example project. Within the SDK for the RT1050-EVKB you will find an example named "flexspi_nor_flash_page_program". Within this project, you will find the drivers fsl_flexspi, these drivers include the function called "FLEXSPI_TransferBlocking". Do you have the same performance if you use this function? 

Regards, 

Victor 

0 项奖励
回复

1,690 次查看
matthiaspimming
Contributor I

Hi Victor,

yes we started with those example design and the FIFO filling was as poor as in our design.

As I already mentioned, could  the Problem be the AHB to IP Bridge?

Which only runs with 24MHz I guess?

Best Regards

0 项奖励
回复

1,690 次查看
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Matthias, 

Could you please share your clock configuration with me? 

Regards, 

Victor 

0 项奖励
回复

1,690 次查看
matthiaspimming
Contributor I

Hi Victor,

attached below you can find the clock configuration of the whole project. Please let me know if you need detailed information about clock configuration.

Thanks for your support so far. I really appreciate that.

BR

#include "fsl_clock.h"
#include "mimxrt_dcdc.h"

#ifdef EVKBOARD
   #define BOARD_BOOTCLOCKRUN_CORE_CLOCK             600000000U  /*!< Core clock frequency: 600000000Hz */
#else
   #define BOARD_BOOTCLOCKRUN_CORE_CLOCK             528000000U  /*!< Core clock frequency: 528000000Hz */
#endif

extern unsigned long SystemCoreClock;

static const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN =
    {
#ifdef EVKBOARD
        100,                // PLL loop divider, Fout = Fin * 50
#else
        88,                 // PLL loop divider, Fout = Fin * 44
#endif
        0,                  // Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N
    };
static const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN =
    {
        0,                  // PLL loop divider, Fout = Fin * 20
        0,                  // Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N
    };
static const clock_video_pll_config_t videoPllConfig_BOARD_BootClockRUN =
    {
        40,                 // PLL loop divider, Fout = Fin * ( loopDivider + numerator / denominator )
        2,                  // Divider after PLL
        0,                  // 30 bit numerator of fractional loop divider, Fout = Fin * ( loopDivider + numerator / denominator )
        1,                  // 30 bit denominator of fractional loop divider, Fout = Fin * ( loopDivider + numerator / denominator )
        0,                  // Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N
    };
static const clock_enet_pll_config_t enetPllConfig_BOARD_BootClockRUN =
    {
        1,                  // Enable the PLL providing the ENET 125MHz reference clock
        1,                  // Enable the PLL providing the ENET 25MHz reference clock
        1,                  // Set frequency of ethernet reference clock to 2.4 MHz
        0,                  // Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N
    };

void BOARD_BootClockRUN(void)
{
    unsigned long pllVideo;
    /* Disable 1MHz clock output. */
    XTALOSC24M->OSC_CONFIG2 &= ~XTALOSC24M_OSC_CONFIG2_ENABLE_1M_MASK;
    /* Set XTAL 24MHz clock frequency. */
    CLOCK_SetXtalFreq(24000000U);
    /* Enable XTAL 24MHz clock source. */
    CLOCK_InitExternalClk(0);
    /* Enable internal RC. */
    CLOCK_InitRcOsc24M();
    /* Switch clock source to external OSC. */
    CLOCK_SwitchOsc(kCLOCK_XtalOsc);
    /* Set Oscillator ready counter value. */
    CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(127);
    /* Setting PeriphClk2Mux and PeriphMux to provide stable clock before PLLs are initialed */
    CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 1); /* Set PERIPH_CLK2 MUX to OSC */
    CLOCK_SetMux(kCLOCK_PeriphMux, 1);     /* Set PERIPH_CLK MUX to PERIPH_CLK2 */
    /* Setting the VDD_SOC to 1.5V. It is necessary to config AHB to 600Mhz. */
    DCDC->REG3 = (DCDC->REG3 & (~DCDC_REG3_TRG_MASK)) | DCDC_REG3_TRG(0x12);
    /* Waiting for DCDC_STS_DC_OK bit is asserted */
    while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & DCDC->REG0))
    {
    }
    /* Init ARM PLL. */
    CLOCK_InitArmPll(&armPllConfig_BOARD_BootClockRUN);
    /* Init Usb1 PLL. */
    CLOCK_InitUsb1Pll(&usb1PllConfig_BOARD_BootClockRUN);
    /* Init Usb1 pfd0. */
    CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 27);
    /* Init Usb1 pfd1. */
    CLOCK_InitUsb1Pfd(kCLOCK_Pfd1, 18);
    /* Init Usb1 pfd2. */
    CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, 17);
    /* Init Usb1 pfd3. */
    CLOCK_InitUsb1Pfd(kCLOCK_Pfd3, 19);
    /* DeInit Audio PLL. */
    CLOCK_DeinitAudioPll();
    /* Bypass Audio PLL. */
    CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllAudio, 1);
    /* Set divider for Audio PLL. */
    CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
    CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK;
    /* Enable Audio PLL output. */
    CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE_MASK;
    /* Init Video PLL. */
    /* Disable Video PLL output before initial Video PLL. */
    CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_ENABLE_MASK;
    /* Bypass PLL first */
    CCM_ANALOG->PLL_VIDEO = (CCM_ANALOG->PLL_VIDEO & (~CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK)) |
                            CCM_ANALOG_PLL_VIDEO_BYPASS_MASK | CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC(0);
    CCM_ANALOG->PLL_VIDEO_NUM = CCM_ANALOG_PLL_VIDEO_NUM_A(0);
    CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(1);
    pllVideo = (CCM_ANALOG->PLL_VIDEO & (~(CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK | CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK))) |
               CCM_ANALOG_PLL_VIDEO_ENABLE_MASK |CCM_ANALOG_PLL_VIDEO_DIV_SELECT(40);
    pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
    CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & (~CCM_ANALOG_MISC2_VIDEO_DIV_MASK)) | CCM_ANALOG_MISC2_VIDEO_DIV(0);
    CCM_ANALOG->PLL_VIDEO = pllVideo;
    while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0)
    {
    }
    /* Disable pfd offset. */
    CCM_ANALOG->PLL_VIDEO &= ~CCM_ANALOG_PLL_VIDEO_PFD_OFFSET_EN_MASK;
    /* Disable bypass for Video PLL. */
    CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllVideo, 0);
    /* Init Enet PLL. */
    CLOCK_InitEnetPll(&enetPllConfig_BOARD_BootClockRUN);
    /* Disable pfd offset. */
    CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_PFD_OFFSET_EN_MASK;
    /* Bypass Enet PLL. */
    CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllEnet, 1);
    /* DeInit Usb2 PLL. */
    CLOCK_DeinitUsb2Pll();
    /* Bypass Usb2 PLL. */
    CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllUsb2, 1);
    /* Enable Usb2 PLL output. */
    CCM_ANALOG->PLL_USB2 |= CCM_ANALOG_PLL_USB2_ENABLE_MASK;
    /* Set AHB_PODF. */
    CLOCK_SetDiv(kCLOCK_AhbDiv, 0);
    /* Set IPG_PODF. */
    CLOCK_SetDiv(kCLOCK_IpgDiv, 3);
    /* Set ARM_PODF. */
    CLOCK_SetDiv(kCLOCK_ArmDiv, 1);
    /* Set preperiph clock source. */
    CLOCK_SetMux(kCLOCK_PrePeriphMux, 3);
    /* Set periph clock source. */
    CLOCK_SetMux(kCLOCK_PeriphMux, 0);
    /* Set PERIPH_CLK2_PODF. */
    CLOCK_SetDiv(kCLOCK_PeriphClk2Div, 0);
    /* Set periph clock2 clock source. */
    CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 1);
    /* Set PERCLK_PODF. */
    CLOCK_SetDiv(kCLOCK_PerclkDiv, 1);
    /* Set per clock source. */
    CLOCK_SetMux(kCLOCK_PerclkMux, 0);
    /* Set USDHC1_PODF. */
    CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1);
    /* Set Usdhc1 clock source. */
    CLOCK_SetMux(kCLOCK_Usdhc1Mux, 1);
    /* Set USDHC2_PODF. */
    CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1);
    /* Set Usdhc2 clock source. */
    CLOCK_SetMux(kCLOCK_Usdhc2Mux, 1);
    /* Set FLEXSPI_PODF. */
    CLOCK_SetDiv(kCLOCK_FlexspiDiv, 0);
    /* Set Flexspi clock source. */
    CLOCK_SetMux(kCLOCK_FlexspiMux, 3);
    /* Set LPSPI_PODF. */
    CLOCK_SetDiv(kCLOCK_LpspiDiv, 3);
    /* Set Lpspi clock source. */
    CLOCK_SetMux(kCLOCK_LpspiMux, 0);
    /* Set TRACE_PODF. */
    CLOCK_SetDiv(kCLOCK_TraceDiv, 2);
    /* Set Trace clock source. */
    CLOCK_SetMux(kCLOCK_TraceMux, 2);
    /* Set SAI1_CLK_PRED. */
    CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3);
    /* Set SAI1_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Sai1Div, 1);
    /* Set Sai1 clock source. */
    CLOCK_SetMux(kCLOCK_Sai1Mux, 0);
    /* Set SAI2_CLK_PRED. */
    CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3);
    /* Set SAI2_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Sai2Div, 1);
    /* Set Sai2 clock source. */
    CLOCK_SetMux(kCLOCK_Sai2Mux, 0);
    /* Set SAI3_CLK_PRED. */
    CLOCK_SetDiv(kCLOCK_Sai3PreDiv, 3);
    /* Set SAI3_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Sai3Div, 1);
    /* Set Sai3 clock source. */
    CLOCK_SetMux(kCLOCK_Sai3Mux, 0);
    /* Set LPI2C_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 0);
    /* Set Lpi2c clock source. */
    CLOCK_SetMux(kCLOCK_Lpi2cMux, 0);
    /* Set CAN_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_CanDiv, 1);
    /* Set Can clock source. */
    CLOCK_SetMux(kCLOCK_CanMux, 2);
    /* Set UART_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_UartDiv, 0);
    /* Set Uart clock source. */
    CLOCK_SetMux(kCLOCK_UartMux, 0);
    /* Set SPDIF0_CLK_PRED. */
    CLOCK_SetDiv(kCLOCK_Spdif0PreDiv, 1);
    /* Set SPDIF0_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Spdif0Div, 7);
    /* Set Spdif clock source. */
    CLOCK_SetMux(kCLOCK_SpdifMux, 3);
    /* Set FLEXIO1_CLK_PRED. */
    CLOCK_SetDiv(kCLOCK_Flexio1PreDiv, 1);
    /* Set FLEXIO1_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Flexio1Div, 7);
    /* Set Flexio1 clock source. */
    CLOCK_SetMux(kCLOCK_Flexio1Mux, 3);
    /* Set FLEXIO2_CLK_PRED. */
    CLOCK_SetDiv(kCLOCK_Flexio2PreDiv, 3);
    /* Set FLEXIO2_CLK_PODF. */
    CLOCK_SetDiv(kCLOCK_Flexio2Div, 0);
    /* Set Flexio2 clock source. */
    CLOCK_SetMux(kCLOCK_Flexio2Mux, 2);
    /* Set Pll3 sw clock source. */
    CLOCK_SetMux(kCLOCK_Pll3SwMux, 0);
    /* Set lvds1 clock source. */
    CCM_ANALOG->MISC1 = (CCM_ANALOG->MISC1 & (~CCM_ANALOG_MISC1_LVDS1_CLK_SEL_MASK)) | CCM_ANALOG_MISC1_LVDS1_CLK_SEL(0);
    /* Set clock out1 divider. */
    CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_DIV_MASK)) | CCM_CCOSR_CLKO1_DIV(0);
    /* Set clock out1 source. */
    CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_SEL_MASK)) | CCM_CCOSR_CLKO1_SEL(1);
    /* Set clock out2 divider. */
    CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_DIV_MASK)) | CCM_CCOSR_CLKO2_DIV(0);
    /* Set clock out2 source. */
    CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_SEL_MASK)) | CCM_CCOSR_CLKO2_SEL(18);
    /* Set clock out1 drives clock out1. */
    CCM->CCOSR &= ~CCM_CCOSR_CLK_OUT_SEL_MASK;
    /* Disable clock out1. */
    CCM->CCOSR &= ~CCM_CCOSR_CLKO1_EN_MASK;
    /* Disable clock out2. */
    CCM->CCOSR &= ~CCM_CCOSR_CLKO2_EN_MASK;

    CLOCK_InitVideoPll(&videoPllConfig_BOARD_BootClockRUN);

    /* Set SystemCoreClock variable. */
    SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK;
    SYSTEMRT1050_CoreClockUpdate();
}

0 项奖励
回复

1,690 次查看
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Matthias, 

Your clock configuration seems to be right. At this point, if you would like to increase the speed while filling the FIFO I would recommend you doing this with the DMA. Section 27.5.9.2 of the RT10150 RM specifies how to achieve this. 

Regards, 

Victor 

0 项奖励
回复

1,690 次查看
victorjimenez
NXP TechSupport
NXP TechSupport

Hi Matthias, 

Could you please share the code that you are using to fill the TX FIFO so I can take a look at it? And also, could you please specify which RT you are using? 

Regards, 

Victor 

0 项奖励
回复