/* * Copyright 2016-2021 NXP * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, this list * of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, this * list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * o Neither the name of NXP Semiconductor, Inc. nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @file i3c_test.c * @brief Application entry point. */ #include #include #include "board.h" #include "peripherals.h" #include "pin_mux.h" #include "clock_config.h" #include "MIMXRT685S_cm33.h" #include "fsl_debug_console.h" #include "fsl_i3c.h" void master_frequency_config(uint8_t main_clk_div_factor, uint8_t ppbaud, uint8_t pplow, uint8_t odbaud, uint8_t skew); void master_init(void); status_t IBHR_Pattern(void); int main(void) { /* Init board hardware. */ BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitBootPeripherals(); #ifndef BOARD_INIT_DEBUG_CONSOLE_PERIPHERAL /* Init FSL debug console. */ BOARD_InitDebugConsole(); #endif PRINTF("I3C timing in this test is expecting Main clock = 500 MHz.\r\n"); PRINTF("Current setup Main clock = %d Hz.\r\n\r\n", CLOCK_GetMainClkFreq()); /* I3C Master initialization */ PRINTF("Initialization of I3C Master\r\n"); master_init(); master_frequency_config(10, 1, 0, 3, 0); // Push-Pull: 12.5MHz, Open-Drain: 5MHz IBHR_Pattern(); return 0 ; } /* * Configure the I3C frequencies acting directly on the uC registers: * Frequency of I3C peripheral I3C_CLK_FREQ = Main_Clock / main_clk_div_factor * Period of I3C peripheral T_CLK = 1 / I3C_CLK_FREQ * High Push-Pull semiperiod THPP = T_CLK * (1 + ppbaud) * Low Push-Pull semiperiod TLPP = T_CLK * (1 + ppbaud + pplow) = THPP + T_CLK*pplow * Push-Pull Bitrate TPP = THPP + TLPP = T_CLK * (2 + 2*ppbaud + pplow) * High Open-Drain semiperiod THOD = THPP * Low Open-Drain semiperiod TLOD = T_CLK * (1 + ppbaud) * (1 + odbaud) = THOD * (1 + odbaud) * Open-Drain Bitrate TOD = THOD + TLOD * SDA skew from SCL SKEW = normal_skew + (T_CLK * skew) * * param main_clk_div_factor division factor of the Main Clock (allowed: 1 to 256) * param ppbaud changes the push-pull high semiperiod (allowed: 0 to 15) * param pplow changes the push-pull high semiperiod (allowed: 0 to 15) * param odbaud changes the open-drain low semiperiod (allowed: 0 to 255) * param skew specifies the number of T_CLKs to add to the normal SCL-to-SDA skew (allowed: 0 to 7) */ void master_frequency_config(uint8_t main_clk_div_factor, uint8_t ppbaud, uint8_t pplow, uint8_t odbaud, uint8_t skew) { uint32_t T_clk, Thpp, Tlpp, Tpp, Tlod, Tod, Skew; CLOCK_SetClkDiv(kCLOCK_DivI3cClk, main_clk_div_factor); // Main Clock / main_clk_div_factor PRINTF("Frequency of Main clock = %d Hz.\r\n", CLOCK_GetMainClkFreq()); PRINTF("Frequency of I3C Peripheral = %d Hz.\r\n", CLOCK_GetI3cClkFreq()); if (ppbaud > 15){ PRINTF("*ERROR: allowed values for ppbaud are 0 to 15\r\n"); } else if (pplow > 15){ PRINTF("*ERROR: allowed values for pplow are 0 to 15\r\n"); } else if (odbaud > 255){ PRINTF("*ERROR: allowed values for odbaud are 0 to 255\r\n"); } else if (skew > 7){ PRINTF("*ERROR: allowed values for skew are 0 to 7\r\n"); } else { I3C->MCONFIG = (I3C->MCONFIG & ~(I3C_MCONFIG_SKEW_MASK | I3C_MCONFIG_PPBAUD_MASK | I3C_MCONFIG_PPLOW_MASK | I3C_MCONFIG_ODBAUD_MASK | I3C_MCONFIG_ODHPP_MASK)) | I3C_MCONFIG_SKEW(skew) | // SKEW = normal_skew + (T_CLK * skew) I3C_MCONFIG_PPBAUD(ppbaud) | // THPP = T_CLK * (1 + ppbaud) I3C_MCONFIG_PPLOW(pplow) | // TLPP = T_CLK * (1 + ppbaud + pplow) I3C_MCONFIG_ODBAUD(odbaud) | // TLOD = THPP * (1 + odbaud) I3C_MCONFIG_ODHPP(1); // masterConfig->enableOpenDrainHigh = true // Quantities in picoseconds T_clk = 1000000000000 / CLOCK_GetI3cClkFreq(); Thpp = T_clk * (1 + ppbaud); Tlpp = T_clk * (1 + ppbaud + pplow); Tpp = Thpp + Tlpp; Tlod = Thpp * (1 + odbaud); Tod = Thpp + Tlod; Skew = T_clk * skew; PRINTF("I3C Peripheral Period = %d.%d ns\r\n", T_clk/1000, T_clk%1000); PRINTF("Push-Pull Bitrate = %d.%d ns (THPP = %d.%d ns, TLPP = %d.%d ns)\r\n", Tpp/1000, Tpp%1000, Thpp/1000, Thpp%1000, Tlpp/1000, Tlpp%1000); PRINTF("Open-Drain Bitrate = %d.%d ns (THOD = %d.%d ns, TLOD = %d.%d ns)\r\n", Tod/1000, Tod%1000, Thpp/1000, Thpp%1000, Tlod/1000, Tlod%1000); PRINTF("Added SCL->SDA skew = %d.%d ns\r\n", Skew/1000, Skew%1000); } } /* * Initialize I3C Master */ void master_init(void) { i3c_master_config_t masterConfig; /* enable clock, reset module */ // Enable the clock to the I3C in the CLKCTL1_PSCCTL2 register.This enables the register interface and the peripheral function clock. CLOCK_SetClkDiv(kCLOCK_DivI3cClk, 40); // Main Clock / 40 = 12.5MHz --> 80ns resolution CLOCK_EnableClock(kCLOCK_I3c0); RESET_PeripheralReset(kI3C0_RST_SHIFT_RSTn); /* Adjust I3C default configuration parameter selection */ I3C_MasterGetDefaultConfig(&masterConfig); masterConfig.hKeep = kI3C_MasterHighKeeperNone; masterConfig.baudRate_Hz.i2cBaud = 400000U; masterConfig.baudRate_Hz.i3cOpenDrainBaud = 1000000U; masterConfig.baudRate_Hz.i3cPushPullBaud = 6000000U; masterConfig.enableOpenDrainStop = false; I3C_MasterInit(I3C, &masterConfig, CLOCK_GetI3cClkFreq()); } /* * Generates the Slave Reset Pattern (In-Band Hardware Reset) * TODO: it doesn't work. It generates the HDR_EXIT pattern */ status_t IBHR_Pattern(void) { I3C->MCTRL = (I3C->MCTRL & ~(I3C_MCTRL_REQUEST_MASK | I3C_MCTRL_TYPE_MASK)) | I3C_MCTRL_REQUEST(6) | I3C_MCTRL_TYPE(3); //I3C->MCTRL = I3C_MCTRL_REQUEST(6) | I3C_MCTRL_TYPE(3); return 0; }