Skip to content

Commit 5354079

Browse files
Lots of K64F SPI fixes (#315)
* Update DSPI driver to latest version from NXP * Other updates to SDK files * Fix double DMA transactions, improve dummy byte support * Simplify dummy byte setting * Also fix SPI driver bug * Fix infinite hang with interrupt SPI * Better fix for SPI hang * Remove earlier fix
1 parent de0c404 commit 5354079

File tree

13 files changed

+1463
-519
lines changed

13 files changed

+1463
-519
lines changed

drivers/include/drivers/SPI.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ class SPI : private NonCopyable<SPI> {
480480
typename std::enable_if<std::is_integral<WordT>::value, int>::type
481481
transfer(const WordT *tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
482482
{
483-
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity()));
483+
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
484484
return transfer_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, callback, event);
485485
}
486486

@@ -489,7 +489,7 @@ class SPI : private NonCopyable<SPI> {
489489
typename std::enable_if<std::is_integral<WordT>::value, int>::type
490490
transfer(const std::nullptr_t tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, const event_callback_t &callback, int event = SPI_EVENT_COMPLETE)
491491
{
492-
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity()));
492+
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
493493
return transfer_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, callback, event);
494494
}
495495
template<typename WordT>
@@ -528,7 +528,7 @@ class SPI : private NonCopyable<SPI> {
528528
typename std::enable_if<std::is_integral<WordT>::value, int>::type
529529
transfer_and_wait(const WordT *tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout = rtos::Kernel::wait_for_u32_forever)
530530
{
531-
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity()));
531+
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
532532
return transfer_and_wait_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, timeout);
533533
}
534534

@@ -537,7 +537,7 @@ class SPI : private NonCopyable<SPI> {
537537
typename std::enable_if<std::is_integral<WordT>::value, int>::type
538538
transfer_and_wait(const std::nullptr_t tx_buffer, int tx_length, CacheAlignedBuffer<WordT> &rx_buffer, int rx_length, rtos::Kernel::Clock::duration_u32 timeout = rtos::Kernel::wait_for_u32_forever)
539539
{
540-
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity()));
540+
MBED_ASSERT(rx_length <= static_cast<int>(rx_buffer.capacity() * sizeof(WordT)));
541541
return transfer_and_wait_internal(tx_buffer, tx_length, rx_buffer.data(), rx_length, timeout);
542542
}
543543
template<typename WordT>
@@ -549,6 +549,8 @@ class SPI : private NonCopyable<SPI> {
549549

550550
/**
551551
* @brief Abort the on-going SPI transfer, if any, and continue with transfers in the queue, if any.
552+
*
553+
* @note If a transfer is aborted, its callback will not be called at all.
552554
*/
553555
void abort_transfer();
554556

hal/include/hal/spi_api.h

+3
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ void spi_free(spi_t *obj);
235235
*
236236
* Set the number of bits per frame, configure clock polarity and phase, shift order and master/slave mode.
237237
* The default bit order is MSB.
238+
*
239+
* This function shall NOT modify the SPI frequency if the SPI frequency has previously been set.
240+
*
238241
* @param[in,out] obj The SPI object to configure
239242
* @param[in] bits The number of bits per frame
240243
* @param[in] mode The SPI mode (clock polarity, phase, and shift direction)

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ target_sources(mbed-mcu-k64f
3838
drivers/fsl_cmp.c
3939
drivers/fsl_cmt.c
4040
drivers/fsl_crc.c
41+
drivers/fsl_common_arm.c
4142
drivers/fsl_dac.c
4243
drivers/fsl_dmamux.c
4344
drivers/fsl_dspi.c

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/drivers/fsl_common.h

+217-218
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
/*
2+
* Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
3+
* Copyright 2016-2021 NXP
4+
* All rights reserved.
5+
*
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*/
8+
9+
#include "fsl_common.h"
10+
11+
/* Component ID definition, used by tools. */
12+
#ifndef FSL_COMPONENT_ID
13+
#define FSL_COMPONENT_ID "platform.drivers.common_arm"
14+
#endif
15+
16+
#ifndef __GIC_PRIO_BITS
17+
#if defined(ENABLE_RAM_VECTOR_TABLE)
18+
uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler)
19+
{
20+
#ifdef __VECTOR_TABLE
21+
#undef __VECTOR_TABLE
22+
#endif
23+
24+
/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */
25+
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
26+
extern uint32_t Image$$VECTOR_ROM$$Base[];
27+
extern uint32_t Image$$VECTOR_RAM$$Base[];
28+
extern uint32_t Image$$RW_m_data$$Base[];
29+
30+
#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base
31+
#define __VECTOR_RAM Image$$VECTOR_RAM$$Base
32+
#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base))
33+
#elif defined(__ICCARM__)
34+
extern uint32_t __RAM_VECTOR_TABLE_SIZE[];
35+
extern uint32_t __VECTOR_TABLE[];
36+
extern uint32_t __VECTOR_RAM[];
37+
#elif defined(__GNUC__)
38+
extern uint32_t __VECTOR_TABLE[];
39+
extern uint32_t __VECTOR_RAM[];
40+
extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[];
41+
uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES);
42+
#endif /* defined(__CC_ARM) || defined(__ARMCC_VERSION) */
43+
uint32_t n;
44+
uint32_t ret;
45+
uint32_t irqMaskValue;
46+
47+
irqMaskValue = DisableGlobalIRQ();
48+
if (SCB->VTOR != (uint32_t)__VECTOR_RAM)
49+
{
50+
/* Copy the vector table from ROM to RAM */
51+
for (n = 0; n < ((uint32_t)__RAM_VECTOR_TABLE_SIZE) / sizeof(uint32_t); n++)
52+
{
53+
__VECTOR_RAM[n] = __VECTOR_TABLE[n];
54+
}
55+
/* Point the VTOR to the position of vector table */
56+
SCB->VTOR = (uint32_t)__VECTOR_RAM;
57+
}
58+
59+
ret = __VECTOR_RAM[(int32_t)irq + 16];
60+
/* make sure the __VECTOR_RAM is noncachable */
61+
__VECTOR_RAM[(int32_t)irq + 16] = irqHandler;
62+
63+
EnableGlobalIRQ(irqMaskValue);
64+
65+
return ret;
66+
}
67+
#endif /* ENABLE_RAM_VECTOR_TABLE. */
68+
#endif /* __GIC_PRIO_BITS. */
69+
70+
#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0))
71+
72+
/*
73+
* When FSL_FEATURE_POWERLIB_EXTEND is defined to non-zero value,
74+
* powerlib should be used instead of these functions.
75+
*/
76+
#if !(defined(FSL_FEATURE_POWERLIB_EXTEND) && (FSL_FEATURE_POWERLIB_EXTEND != 0))
77+
78+
/*
79+
* When the SYSCON STARTER registers are discontinuous, these functions are
80+
* implemented in fsl_power.c.
81+
*/
82+
#if !(defined(FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS) && FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS)
83+
84+
void EnableDeepSleepIRQ(IRQn_Type interrupt)
85+
{
86+
uint32_t intNumber = (uint32_t)interrupt;
87+
88+
uint32_t index = 0;
89+
90+
while (intNumber >= 32u)
91+
{
92+
index++;
93+
intNumber -= 32u;
94+
}
95+
96+
SYSCON->STARTERSET[index] = 1UL << intNumber;
97+
(void)EnableIRQ(interrupt); /* also enable interrupt at NVIC */
98+
}
99+
100+
void DisableDeepSleepIRQ(IRQn_Type interrupt)
101+
{
102+
uint32_t intNumber = (uint32_t)interrupt;
103+
104+
(void)DisableIRQ(interrupt); /* also disable interrupt at NVIC */
105+
uint32_t index = 0;
106+
107+
while (intNumber >= 32u)
108+
{
109+
index++;
110+
intNumber -= 32u;
111+
}
112+
113+
SYSCON->STARTERCLR[index] = 1UL << intNumber;
114+
}
115+
#endif /* FSL_FEATURE_SYSCON_STARTER_DISCONTINUOUS */
116+
#endif /* FSL_FEATURE_POWERLIB_EXTEND */
117+
#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */
118+
119+
#if defined(SDK_DELAY_USE_DWT) && defined(DWT)
120+
/* Use WDT. */
121+
static void enableCpuCycleCounter(void)
122+
{
123+
/* Make sure the DWT trace fucntion is enabled. */
124+
if (CoreDebug_DEMCR_TRCENA_Msk != (CoreDebug_DEMCR_TRCENA_Msk & CoreDebug->DEMCR))
125+
{
126+
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
127+
}
128+
129+
/* CYCCNT not supported on this device. */
130+
assert(DWT_CTRL_NOCYCCNT_Msk != (DWT->CTRL & DWT_CTRL_NOCYCCNT_Msk));
131+
132+
/* Read CYCCNT directly if CYCCENT has already been enabled, otherwise enable CYCCENT first. */
133+
if (DWT_CTRL_CYCCNTENA_Msk != (DWT_CTRL_CYCCNTENA_Msk & DWT->CTRL))
134+
{
135+
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
136+
}
137+
}
138+
139+
static uint32_t getCpuCycleCount(void)
140+
{
141+
return DWT->CYCCNT;
142+
}
143+
#else /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */
144+
/* Use software loop. */
145+
#if defined(__CC_ARM) /* This macro is arm v5 specific */
146+
/* clang-format off */
147+
__ASM static void DelayLoop(uint32_t count)
148+
{
149+
loop
150+
SUBS R0, R0, #1
151+
CMP R0, #0
152+
BNE loop
153+
BX LR
154+
}
155+
/* clang-format on */
156+
#elif defined(__ARMCC_VERSION) || defined(__ICCARM__) || defined(__GNUC__)
157+
/* Cortex-M0 has a smaller instruction set, SUBS isn't supported in thumb-16 mode reported from __GNUC__ compiler,
158+
* use SUB and CMP here for compatibility */
159+
static void DelayLoop(uint32_t count)
160+
{
161+
__ASM volatile(" MOV R0, %0" : : "r"(count));
162+
__ASM volatile(
163+
"loop: \n"
164+
#if defined(__GNUC__) && !defined(__ARMCC_VERSION)
165+
" SUB R0, R0, #1 \n"
166+
#else
167+
" SUBS R0, R0, #1 \n"
168+
#endif
169+
" CMP R0, #0 \n"
170+
171+
" BNE loop \n"
172+
:
173+
:
174+
: "r0");
175+
}
176+
#endif /* defined(__CC_ARM) */
177+
#endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */
178+
179+
/*!
180+
* @brief Delay at least for some time.
181+
* Please note that, if not uses DWT, this API will use while loop for delay, different run-time environments have
182+
* effect on the delay time. If precise delay is needed, please enable DWT delay. The two parmeters delayTime_us and
183+
* coreClock_Hz have limitation. For example, in the platform with 1GHz coreClock_Hz, the delayTime_us only supports
184+
* up to 4294967 in current code. If long time delay is needed, please implement a new delay function.
185+
*
186+
* @param delayTime_us Delay time in unit of microsecond.
187+
* @param coreClock_Hz Core clock frequency with Hz.
188+
*/
189+
void SDK_DelayAtLeastUs(uint32_t delayTime_us, uint32_t coreClock_Hz)
190+
{
191+
uint64_t count;
192+
193+
if (delayTime_us > 0U)
194+
{
195+
count = USEC_TO_COUNT(delayTime_us, coreClock_Hz);
196+
197+
assert(count <= UINT32_MAX);
198+
199+
#if defined(SDK_DELAY_USE_DWT) && defined(DWT) /* Use DWT for better accuracy */
200+
201+
enableCpuCycleCounter();
202+
/* Calculate the count ticks. */
203+
count += getCpuCycleCount();
204+
205+
if (count > UINT32_MAX)
206+
{
207+
count -= UINT32_MAX;
208+
/* Wait for cyccnt overflow. */
209+
while (count < getCpuCycleCount())
210+
{
211+
}
212+
}
213+
214+
/* Wait for cyccnt reach count value. */
215+
while (count > getCpuCycleCount())
216+
{
217+
}
218+
#else
219+
/* Divide value may be different in various environment to ensure delay is precise.
220+
* Every loop count includes three instructions, due to Cortex-M7 sometimes executes
221+
* two instructions in one period, through test here set divide 1.5. Other M cores use
222+
* divide 4. By the way, divide 1.5 or 4 could let the count lose precision, but it does
223+
* not matter because other instructions outside while loop is enough to fill the time.
224+
*/
225+
#if (__CORTEX_M == 7)
226+
count = count / 3U * 2U;
227+
#else
228+
count = count / 4U;
229+
#endif
230+
DelayLoop((uint32_t)count);
231+
#endif /* defined(SDK_DELAY_USE_DWT) && defined(DWT) */
232+
}
233+
}

0 commit comments

Comments
 (0)