Skip to content

Commit

Permalink
Some fixes for Teensy4 (#272)
Browse files Browse the repository at this point in the history
* Fix teensy4 build

* Try and fix SCLK clock period issue for MIMXRT, add additional SPI pinmappings

* Add full UART pinmapping

* Make more robust to calling spi_format() after spi_frequency()

* Fix style

---------

Co-authored-by: Jamie Smith <[email protected]>
  • Loading branch information
1 parent 04db467 commit e8b6238
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 10 deletions.
12 changes: 10 additions & 2 deletions hal/include/hal/spi_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,23 @@ void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap);

/** Initialize the SPI peripheral
*
* Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral
* Configures the pins used by SPI and enables the peripheral.
*
* After this function is called by the driver layer, spi_format() and spi_frequency() will
* be called *before* the SPI bus is used.
*
* @param[out] obj The SPI object to initialize
* @param[in] pinmap pointer to structure which holds static pinmap
*/
void spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap);

/** Initialize the SPI peripheral
*
* Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral
* Configures the pins used by SPI and enables the peripheral
*
* After this function is called by the driver layer, spi_format() and spi_frequency() will
* be called *before* the SPI bus is used.
*
* @param[out] obj The SPI object to initialize
* @param[in] mosi The pin to use for MOSI
* @param[in] miso The pin to use for MISO
Expand Down
2 changes: 2 additions & 0 deletions platform/source/mbed_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ static inline bool mbed_error_is_hw_fault(mbed_error_status_t error_status)
error_status == MBED_ERROR_HARDFAULT_EXCEPTION);
}

#ifdef MBED_CONF_RTOS_PRESENT
static bool mbed_error_is_handler(const mbed_error_ctx *ctx)
{
bool is_handler = false;
Expand All @@ -133,6 +134,7 @@ static bool mbed_error_is_handler(const mbed_error_ctx *ctx)
}
return is_handler;
}
#endif

//Set an error status with the error handling system
static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller)
Expand Down
1 change: 1 addition & 0 deletions platform/source/mbed_sdk_boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* limitations under the License.
*/

#include "mbed_error.h"
#include "mbed_toolchain.h"
#include <stdlib.h>
#include <stdint.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct i2c_s {
struct spi_s {
uint32_t instance;
uint8_t bits;
uint32_t frequency;
};

struct dac_s {
Expand Down
59 changes: 54 additions & 5 deletions targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_IMX/spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,25 @@ static LPSPI_Type *const spi_address[] = LPSPI_BASE_PTRS;
extern uint32_t spi_get_clock(void);
extern void spi_setup_clock();

void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName sclk)
{
// determine the SPI to use
uint32_t spi_mosi = pinmap_peripheral(mosi, PinMap_SPI_MOSI);
uint32_t spi_miso = pinmap_peripheral(miso, PinMap_SPI_MISO);
uint32_t spi_sclk = pinmap_peripheral(sclk, PinMap_SPI_SCLK);
uint32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL);
uint32_t spi_data = pinmap_merge(spi_mosi, spi_miso);
uint32_t spi_cntl = pinmap_merge(spi_sclk, spi_ssel);

obj->instance = pinmap_merge(spi_data, spi_cntl);
SPIName spi_instance = pinmap_merge(spi_sclk, spi_data);
return spi_instance;
}

void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
{
// determine the SPI to use
SPIName spi_for_data_lines = spi_get_peripheral_name(mosi, miso, sclk);
uint32_t spi_ssel = pinmap_peripheral(ssel, PinMap_SPI_SSEL);
uint32_t spi_cntl = pinmap_merge(spi_for_data_lines, spi_ssel);

obj->instance = pinmap_merge(spi_for_data_lines, spi_cntl);
MBED_ASSERT((int)obj->instance != NC);

// pin out the spi pins
Expand All @@ -53,6 +61,10 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
pinmap_pinout(ssel, PinMap_SPI_SSEL);
}

// Default frequency (just so we have something to set if spi_format() is called
// before spi_frequency())
obj->frequency = 1000000;

spi_setup_clock();
}

Expand All @@ -61,6 +73,30 @@ void spi_free(spi_t *obj)
LPSPI_Deinit(spi_address[obj->instance]);
}

/*
* This function updates the `CCR.DBT` bitfield, which controls the length of the half
* clock cycle between the end of one frame and the start of the next when in continuous mode.
* It must be updated whenever the SPI clock frequency is changed.
*
* The MIMXRT HAL does not properly set this register so we end up with clock glitches
* when doing multibyte SPI transfers.
*
* Note: The LPSPI must be disabled when calling this function.
*/
static void mimxrt_spi_update_dbt(LPSPI_Type * spibase)
{
// Step 1: Get the current SCLK period, in LPSPI functional clock periods, that was calculated by
// LPSPI_MasterSetBaudRate(). This is given by the CCR.SCKDIV bitfield plus 2.
const uint32_t sclkPeriodClocks = ((spibase->CCR & LPSPI_CCR_SCKDIV_MASK) >> LPSPI_CCR_SCKDIV_SHIFT) + 2;

// Step 2: Divide by 2, rounding up
const uint32_t sclkLowTimeClocks = (sclkPeriodClocks + 1) / 2;

// Step 3: Set this value into the DBT field. The value used by HW is one higher than the value in the register
// so we have to subtract.
spibase->CCR = (spibase->CCR & ~LPSPI_CCR_DBT_MASK) | LPSPI_CCR_DBT(sclkLowTimeClocks - 1);
}

void spi_format(spi_t *obj, int bits, int mode, int slave)
{
lpspi_master_config_t master_config;
Expand All @@ -74,14 +110,21 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
slave_config.cpha = (mode & 0x1) ? kLPSPI_ClockPhaseSecondEdge : kLPSPI_ClockPhaseFirstEdge;
LPSPI_SlaveInit(spi_address[obj->instance], &slave_config);
} else {

/* Master config */
LPSPI_MasterGetDefaultConfig(&master_config);
master_config.bitsPerFrame = (uint32_t)bits;;
master_config.cpol = (mode & 0x2) ? kLPSPI_ClockPolarityActiveLow : kLPSPI_ClockPolarityActiveHigh;
master_config.cpha = (mode & 0x1) ? kLPSPI_ClockPhaseSecondEdge : kLPSPI_ClockPhaseFirstEdge;
master_config.direction = kLPSPI_MsbFirst;
master_config.baudRate = obj->frequency;

LPSPI_MasterInit(spi_address[obj->instance], &master_config, spi_get_clock());

// Update the DBT field which gets overwritten by LPSPI_MasterInit
LPSPI_Enable(spi_address[obj->instance], false);
mimxrt_spi_update_dbt(spi_address[obj->instance]);
LPSPI_Enable(spi_address[obj->instance], true);
}
}

Expand All @@ -97,8 +140,14 @@ void spi_frequency(spi_t *obj, int hz)

spibase->TCR = (spibase->TCR & ~LPSPI_TCR_PRESCALE_MASK) | LPSPI_TCR_PRESCALE(tcrPrescaleValue);

// Update the DBT field which gets overwritten by LPSPI_MasterSetBaudRate
mimxrt_spi_update_dbt(spi_address[obj->instance]);

/* Enable the LPSPI module */
LPSPI_Enable(spibase, true);

// Save frequency for later
obj->frequency = hz;
}

static inline int spi_readable(spi_t * obj)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ typedef enum {
DAC_0 = 0
} DACName;


#define DEVICE_SPI_COUNT 4
typedef enum {
SPI_1 = 1,
SPI_2 = 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,37 +109,107 @@ const PinMap PinMap_I2C_SCL[] = {
/************UART***************/
const PinMap PinMap_UART_TX[] = {
{GPIO_AD_B0_12, UART_1, 2},

{GPIO_SD_B1_11, UART_2, ((0 << DAISY_REG_VALUE_SHIFT) | (0x530 << DAISY_REG_SHIFT) | 2)},
{GPIO_AD_B1_02, UART_2, ((1 << DAISY_REG_VALUE_SHIFT) | (0x530 << DAISY_REG_SHIFT) | 2)},

{GPIO_AD_B1_06, UART_3, ((0 << DAISY_REG_VALUE_SHIFT) | (0x53C << DAISY_REG_SHIFT) | 2)},
{GPIO_EMC_13 , UART_3, ((1 << DAISY_REG_VALUE_SHIFT) | (0x53C << DAISY_REG_SHIFT) | 2)},
{GPIO_B0_08 , UART_3, ((2 << DAISY_REG_VALUE_SHIFT) | (0x53C << DAISY_REG_SHIFT) | 3)},

{GPIO_SD_B1_00, UART_4, ((0 << DAISY_REG_VALUE_SHIFT) | (0x544 << DAISY_REG_SHIFT) | 4)},
{GPIO_EMC_19 , UART_4, ((1 << DAISY_REG_VALUE_SHIFT) | (0x544 << DAISY_REG_SHIFT) | 2)},
{GPIO_B1_00 , UART_4, ((2 << DAISY_REG_VALUE_SHIFT) | (0x544 << DAISY_REG_SHIFT) | 2)},

{GPIO_EMC_23 , UART_5, ((0 << DAISY_REG_VALUE_SHIFT) | (0x54C << DAISY_REG_SHIFT) | 2)},
{GPIO_B1_12 , UART_5, ((1 << DAISY_REG_VALUE_SHIFT) | (0x54C << DAISY_REG_SHIFT) | 1)},

{GPIO_EMC_25 , UART_6, ((0 << DAISY_REG_VALUE_SHIFT) | (0x554 << DAISY_REG_SHIFT) | 2)},
{GPIO_AD_B0_02, UART_6, ((1 << DAISY_REG_VALUE_SHIFT) | (0x554 << DAISY_REG_SHIFT) | 2)},

{GPIO_SD_B1_08, UART_7, ((0 << DAISY_REG_VALUE_SHIFT) | (0x55C << DAISY_REG_SHIFT) | 2)},
{GPIO_EMC_31 , UART_7, ((1 << DAISY_REG_VALUE_SHIFT) | (0x55C << DAISY_REG_SHIFT) | 2)},

{GPIO_SD_B0_04, UART_8, ((0 << DAISY_REG_VALUE_SHIFT) | (0x564 << DAISY_REG_SHIFT) | 2)},
{GPIO_AD_B1_10, UART_8, ((1 << DAISY_REG_VALUE_SHIFT) | (0x564 << DAISY_REG_SHIFT) | 2)},
{GPIO_EMC_38 , UART_8, ((2 << DAISY_REG_VALUE_SHIFT) | (0x564 << DAISY_REG_SHIFT) | 2)},

{NC , NC , 0}
};

const PinMap PinMap_UART_RX[] = {
{GPIO_AD_B0_13, UART_1, 2},

{GPIO_SD_B1_10, UART_2, ((0 << DAISY_REG_VALUE_SHIFT) | (0x52C << DAISY_REG_SHIFT) | 2)},
{GPIO_AD_B1_03, UART_2, ((1 << DAISY_REG_VALUE_SHIFT) | (0x52C << DAISY_REG_SHIFT) | 2)},

{GPIO_AD_B1_07, UART_3, ((0 << DAISY_REG_VALUE_SHIFT) | (0x538 << DAISY_REG_SHIFT) | 2)},
{GPIO_EMC_14 , UART_3, ((1 << DAISY_REG_VALUE_SHIFT) | (0x538 << DAISY_REG_SHIFT) | 2)},
{GPIO_B0_09 , UART_3, ((2 << DAISY_REG_VALUE_SHIFT) | (0x538 << DAISY_REG_SHIFT) | 3)},

{GPIO_SD_B1_01, UART_4, ((0 << DAISY_REG_VALUE_SHIFT) | (0x540 << DAISY_REG_SHIFT) | 4)},
{GPIO_EMC_20 , UART_4, ((1 << DAISY_REG_VALUE_SHIFT) | (0x540 << DAISY_REG_SHIFT) | 2)},
{GPIO_B1_01 , UART_4, ((2 << DAISY_REG_VALUE_SHIFT) | (0x540 << DAISY_REG_SHIFT) | 2)},

{GPIO_EMC_24 , UART_5, ((0 << DAISY_REG_VALUE_SHIFT) | (0x548 << DAISY_REG_SHIFT) | 2)},
{GPIO_B1_13 , UART_5, ((1 << DAISY_REG_VALUE_SHIFT) | (0x548 << DAISY_REG_SHIFT) | 1)},

{GPIO_EMC_26 , UART_6, ((0 << DAISY_REG_VALUE_SHIFT) | (0x550 << DAISY_REG_SHIFT) | 2)},
{GPIO_AD_B0_03, UART_6, ((1 << DAISY_REG_VALUE_SHIFT) | (0x550 << DAISY_REG_SHIFT) | 2)},

{GPIO_SD_B1_09, UART_7, ((0 << DAISY_REG_VALUE_SHIFT) | (0x558 << DAISY_REG_SHIFT) | 2)},
{GPIO_EMC_32 , UART_7, ((1 << DAISY_REG_VALUE_SHIFT) | (0x558 << DAISY_REG_SHIFT) | 2)},

{GPIO_SD_B0_05, UART_8, ((0 << DAISY_REG_VALUE_SHIFT) | (0x560 << DAISY_REG_SHIFT) | 2)},
{GPIO_AD_B1_11, UART_8, ((1 << DAISY_REG_VALUE_SHIFT) | (0x560 << DAISY_REG_SHIFT) | 2)},
{GPIO_EMC_39 , UART_8, ((2 << DAISY_REG_VALUE_SHIFT) | (0x560 << DAISY_REG_SHIFT) | 2)},

{NC , NC , 0}
};

/************SPI***************/
const PinMap PinMap_SPI_SCLK[] = {
{GPIO_EMC_27, SPI_1, ((0U << DAISY_REG_VALUE_SHIFT) | (0x4F0 << DAISY_REG_SHIFT) | 3)},
{GPIO_SD_B0_00, SPI_1, ((1U << DAISY_REG_VALUE_SHIFT) | (0x4F0 << DAISY_REG_SHIFT) | 4)},

{GPIO_SD_B1_07, SPI_2, ((0U << DAISY_REG_VALUE_SHIFT) | (0x500 << DAISY_REG_SHIFT) | 4)},
{GPIO_EMC_00, SPI_2, ((1U << DAISY_REG_VALUE_SHIFT) | (0x500 << DAISY_REG_SHIFT) | 2)},

{GPIO_AD_B0_00, SPI_3, ((0U << DAISY_REG_VALUE_SHIFT) | (0x510 << DAISY_REG_SHIFT) | 7)},
{GPIO_AD_B1_15, SPI_3, ((1U << DAISY_REG_VALUE_SHIFT) | (0x510 << DAISY_REG_SHIFT) | 2)},

{GPIO_B0_03, SPI_4, ((0U << DAISY_REG_VALUE_SHIFT) | (0x520 << DAISY_REG_SHIFT) | 3)},
{GPIO_B1_07, SPI_4, ((1U << DAISY_REG_VALUE_SHIFT) | (0x520 << DAISY_REG_SHIFT) | 1)},
{NC , NC , 0}
};

const PinMap PinMap_SPI_MOSI[] = {
{GPIO_EMC_28, SPI_1, ((0U << DAISY_REG_VALUE_SHIFT) | (0x4F8 << DAISY_REG_SHIFT) | 3)},
{GPIO_SD_B0_02, SPI_1, ((1U << DAISY_REG_VALUE_SHIFT) | (0x4F8 << DAISY_REG_SHIFT) | 4)},

{GPIO_SD_B1_08, SPI_2, ((0U << DAISY_REG_VALUE_SHIFT) | (0x508 << DAISY_REG_SHIFT) | 4)},
{GPIO_EMC_02, SPI_2, ((1U << DAISY_REG_VALUE_SHIFT) | (0x508 << DAISY_REG_SHIFT) | 2)},

{GPIO_AD_B0_01, SPI_3, ((0U << DAISY_REG_VALUE_SHIFT) | (0x518 << DAISY_REG_SHIFT) | 7)},
{GPIO_AD_B1_14, SPI_3, ((1U << DAISY_REG_VALUE_SHIFT) | (0x518 << DAISY_REG_SHIFT) | 2)},

{GPIO_B0_02, SPI_4, ((0U << DAISY_REG_VALUE_SHIFT) | (0x528 << DAISY_REG_SHIFT) | 3)},
{GPIO_B1_06, SPI_4, ((1U << DAISY_REG_VALUE_SHIFT) | (0x528 << DAISY_REG_SHIFT) | 1)},
{NC , NC , 0}
};

const PinMap PinMap_SPI_MISO[] = {
{GPIO_EMC_29, SPI_1, ((0U << DAISY_REG_VALUE_SHIFT) | (0x4F4 << DAISY_REG_SHIFT) | 3)},
{GPIO_SD_B0_03, SPI_1, ((1U << DAISY_REG_VALUE_SHIFT) | (0x4F4 << DAISY_REG_SHIFT) | 4)},

{GPIO_SD_B1_09, SPI_2, ((0U << DAISY_REG_VALUE_SHIFT) | (0x504 << DAISY_REG_SHIFT) | 4)},
{GPIO_EMC_03, SPI_2, ((1U << DAISY_REG_VALUE_SHIFT) | (0x504 << DAISY_REG_SHIFT) | 2)},

{GPIO_AD_B0_02, SPI_3, ((0U << DAISY_REG_VALUE_SHIFT) | (0x514 << DAISY_REG_SHIFT) | 7)},
{GPIO_AD_B1_13, SPI_3, ((1U << DAISY_REG_VALUE_SHIFT) | (0x514 << DAISY_REG_SHIFT) | 2)},

{GPIO_B0_01, SPI_4, ((0U << DAISY_REG_VALUE_SHIFT) | (0x524 << DAISY_REG_SHIFT) | 3)},
{GPIO_B1_05, SPI_4, ((1U << DAISY_REG_VALUE_SHIFT) | (0x524 << DAISY_REG_SHIFT) | 1)},
{NC , NC , 0}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
*/

#include <stdint.h>
#include <mimxrt_flash_info.h>
#include <mimxrt_memory_info.h>

extern void Reset_Handler(void);
extern unsigned long _estack;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ typedef enum {
DAC_0 = 0
} DACName;


#define DEVICE_SPI_COUNT 3
typedef enum {
SPI_1 = 1,
SPI_2 = 2,
Expand Down

0 comments on commit e8b6238

Please sign in to comment.