Skip to content

Commit f37ade1

Browse files
committed
Add reference implementation for the FRDM-K66F.
It only supports I²S 16bit data 32bit word Stereo at 16000 sample/second. The actual implementation might not reflect exactly what the format structure requires.
1 parent dc2ad67 commit f37ade1

File tree

8 files changed

+283
-6
lines changed

8 files changed

+283
-6
lines changed

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/PeripheralNames.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ typedef enum {
131131
SPI_2 = 2,
132132
} SPIName;
133133

134+
typedef enum {
135+
SAI_0 = 0
136+
} SAIName;
137+
134138
#ifdef __cplusplus
135139
}
136140
#endif

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/PeripheralPins.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,3 +299,65 @@ const PinMap PinMap_PWM[] = {
299299

300300
{NC , NC , 0}
301301
};
302+
303+
/************I2S***************/
304+
const PinMap PinMap_SAI_MCLK[] = {
305+
{PTA17, SAI_0, 6},
306+
{PTC6 , SAI_0, 6},
307+
{PTC8 , SAI_0, 4},
308+
{PTE6 , SAI_0, 4},
309+
310+
{NC , NC, 0}
311+
};
312+
const PinMap PinMap_SAI_TXSD[] = {
313+
{PTA12, SAI_0, 6},
314+
{PTA14, SAI_0, 7},
315+
{PTC0 , SAI_0, 6},
316+
{PTC1 , SAI_0, 6},
317+
{PTE9 , SAI_0, 2},
318+
{PTE10, SAI_0, 4},
319+
320+
{NC , NC, 0}
321+
};
322+
const PinMap PinMap_SAI_TXBCLK[] = {
323+
{PTA5 , SAI_0, 6},
324+
{PTB18, SAI_0, 4},
325+
{PTC3 , SAI_0, 6},
326+
{PTE12, SAI_0, 4},
327+
328+
{NC , NC, 0}
329+
};
330+
const PinMap PinMap_SAI_TXWCLK[] = {
331+
{PTA13, SAI_0, 6},
332+
{PTB19, SAI_0, 4},
333+
{PTC2 , SAI_0, 6},
334+
{PTE11, SAI_0, 4},
335+
336+
{NC , NC, 0}
337+
};
338+
const PinMap PinMap_SAI_RXSD[] = {
339+
{PTA15, SAI_0, 6},
340+
{PTA16, SAI_0, 7},
341+
{PTC5 , SAI_0, 4},
342+
{PTC11, SAI_0, 4},
343+
{PTE7 , SAI_0, 4},
344+
{PTE8 , SAI_0, 2},
345+
346+
{NC , NC, 0}
347+
};
348+
const PinMap PinMap_SAI_RXBCLK[] = {
349+
{PTA14, SAI_0, 6},
350+
{PTC6 , SAI_0, 4},
351+
{PTC9 , SAI_0, 4},
352+
{PTE9 , SAI_0, 4},
353+
354+
{NC , NC, 0}
355+
};
356+
const PinMap PinMap_SAI_RXWCLK[] = {
357+
{PTA16, SAI_0, 6},
358+
{PTC7 , SAI_0, 4},
359+
{PTC10, SAI_0, 4},
360+
{PTE8 , SAI_0, 4},
361+
362+
{NC, NC, 0}
363+
};

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/PinNames.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ typedef enum {
191191
PTE30 = (4 << GPIO_PORT_SHIFT | 30),
192192
PTE31 = (4 << GPIO_PORT_SHIFT | 31),
193193

194+
// Not connected
195+
NC = (int)0xFFFFFFFF,
196+
197+
// common name
194198
LED_RED = PTC9,
195199
LED_GREEN = PTE6,
196200
LED_BLUE = PTA11,
@@ -212,6 +216,16 @@ typedef enum {
212216
USBTX = PTB17,
213217
USBRX = PTB16,
214218

219+
// Audio bus
220+
SAI_A_MCLK = PTC6,
221+
SAI_A_SD = PTE7,
222+
SAI_A_BCLK = PTE9,
223+
SAI_A_WCLK = PTE8,
224+
SAI_B_MCLK = PTC6,
225+
SAI_B_SD = PTC1,
226+
SAI_B_BCLK = PTE12,
227+
SAI_B_WCLK = PTE11,
228+
215229
// Arduino Headers
216230
D0 = PTC3,
217231
D1 = PTC4,
@@ -241,9 +255,6 @@ typedef enum {
241255
A5 = PTB2,
242256

243257
DAC0_OUT = 0xFEFE, /* DAC does not have Pin Name in RM */
244-
245-
// Not connected
246-
NC = (int)0xFFFFFFFF
247258
} PinName;
248259

249260

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/device.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727

2828

29-
29+
#define SAI_DEFAULT_SAMPLE_RATE (16000)
3030

3131
#define DEVICE_ID_LENGTH 24
3232

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2018 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "sai_api.h"
17+
18+
#if DEVICE_SAI
19+
20+
// math.h required for floating point operations for baud rate calculation
21+
#include <math.h>
22+
#include "mbed_assert.h"
23+
24+
#include <string.h>
25+
26+
#include "cmsis.h"
27+
#include "pinmap.h"
28+
#include "fsl_sai.h"
29+
#include "peripheral_clock_defines.h"
30+
#include "PeripheralPins.h"
31+
#include "fsl_clock_config.h"
32+
33+
static I2S_Type *const sai_addrs[] = I2S_BASE_PTRS;
34+
35+
sai_result_t sai_init(sai_t *obj, sai_init_t *init) {
36+
int32_t base = NC;
37+
int32_t tx = NC;
38+
int32_t rx = NC;
39+
40+
MBED_ASSERT(init != NULL);
41+
if (memcmp(&(init->format), &sai_mode_i2s16w32, sizeof(sai_format_t)) != 0) {
42+
// we only support 1 format so far
43+
return SAI_RESULT_CONFIG_UNSUPPORTED;
44+
}
45+
if ((init->mclk_source != SAI_CLOCK_SOURCE_Internal) || (init->input_mclk_frequency != 0)) {
46+
return SAI_RESULT_CONFIG_UNSUPPORTED;
47+
}
48+
uint32_t mclk_freq = CLOCK_GetFreq(kCLOCK_CoreSysClk);
49+
50+
obj->is_receiver = init->is_receiver;
51+
52+
// validate pins & fetch base peripheral address
53+
int32_t mclk = pinmap_peripheral(init->mclk, PinMap_SAI_MCLK);
54+
if (obj->is_receiver) {
55+
int32_t sd = pinmap_peripheral(init->sd, PinMap_SAI_RXSD);
56+
int32_t bclk = pinmap_peripheral(init->bclk, PinMap_SAI_RXBCLK);
57+
int32_t wclk = pinmap_peripheral(init->wclk, PinMap_SAI_RXWCLK);
58+
MBED_ASSERT((sd != NC) && (bclk != NC) && (wclk != NC));
59+
rx = pinmap_merge(pinmap_merge(sd, bclk), wclk);
60+
MBED_ASSERT(rx != NC);
61+
} else {
62+
int32_t sd = pinmap_peripheral(init->sd, PinMap_SAI_TXSD);
63+
int32_t bclk = pinmap_peripheral(init->bclk, PinMap_SAI_TXBCLK);
64+
int32_t wclk = pinmap_peripheral(init->wclk, PinMap_SAI_TXWCLK);
65+
MBED_ASSERT((sd != NC) && (bclk != NC) && (wclk != NC));
66+
tx = pinmap_merge(pinmap_merge(sd, bclk), wclk);
67+
MBED_ASSERT(tx != NC);
68+
}
69+
base = pinmap_merge(pinmap_merge(tx, rx), mclk);
70+
MBED_ASSERT(base != NC);
71+
72+
obj->base = sai_addrs[base];
73+
74+
// enable recv
75+
sai_config_t config;
76+
sai_transfer_format_t format;
77+
78+
if (init->mclk != NC) {
79+
pinmap_pinout(init->mclk, PinMap_SAI_MCLK);
80+
}
81+
if (obj->is_receiver) {
82+
if (init->sd != NC) {
83+
pinmap_pinout(init->sd, PinMap_SAI_RXSD);
84+
}
85+
if (init->bclk != NC) {
86+
pinmap_pinout(init->bclk, PinMap_SAI_RXBCLK);
87+
}
88+
if (init->wclk != NC) {
89+
pinmap_pinout(init->wclk, PinMap_SAI_RXWCLK);
90+
}
91+
92+
/* Initialize SAI Rx */
93+
SAI_RxGetDefaultConfig(&config);
94+
} else {
95+
if (init->sd != NC) {
96+
pinmap_pinout(init->sd, PinMap_SAI_TXSD);
97+
}
98+
if (init->bclk != NC) {
99+
pinmap_pinout(init->bclk, PinMap_SAI_TXBCLK);
100+
}
101+
if (init->wclk != NC) {
102+
pinmap_pinout(init->wclk, PinMap_SAI_TXWCLK);
103+
}
104+
105+
SAI_TxGetDefaultConfig(&config);
106+
}
107+
108+
obj->channel = 0U; // we should get it from the sd pin
109+
110+
config.protocol = kSAI_BusI2S;
111+
112+
if (init->is_receiver) {
113+
config.masterSlave = kSAI_Slave;
114+
SAI_RxInit(obj->base, &config);
115+
} else {
116+
SAI_TxInit(obj->base, &config);
117+
}
118+
119+
/* Configure the audio format */
120+
format.bitWidth = init->format.data_length;
121+
format.channel = obj->channel;
122+
format.sampleRate_Hz = init->sample_rate;
123+
format.masterClockHz = init->output_mclk_frequency;
124+
125+
format.protocol = config.protocol;
126+
format.stereo = kSAI_Stereo;
127+
// FSL_FEATURE_SAI_FIFO_COUNT = 8 on MK66F18
128+
format.watermark = FSL_FEATURE_SAI_FIFO_COUNT / 2U;
129+
130+
if (obj->is_receiver) {
131+
SAI_RxSetFormat(obj->base, &format, mclk_freq, format.masterClockHz);
132+
} else {
133+
SAI_TxSetFormat(obj->base, &format, mclk_freq, format.masterClockHz);
134+
}
135+
136+
return SAI_RESULT_OK;
137+
}
138+
139+
bool sai_xfer(sai_t *obj, uint32_t *sample) {
140+
bool ret = false;
141+
if (obj->is_receiver) {
142+
if (sample != NULL) {
143+
uint32_t flags = SAI_RxGetStatusFlag(obj->base);
144+
if ((flags & I2S_RCSR_RE_MASK) == 0) {
145+
SAI_RxEnable(obj->base, true);
146+
}
147+
ret = (flags & I2S_RCSR_FRF_MASK) == I2S_RCSR_FRF_MASK;
148+
if (ret) {
149+
*sample = SAI_ReadData(obj->base, obj->channel);
150+
}
151+
if ((flags & I2S_RCSR_FEF_MASK) == I2S_RCSR_FEF_MASK) {
152+
SAI_RxClearStatusFlags(obj->base, I2S_RCSR_FEF_MASK);
153+
}
154+
}
155+
} else {
156+
uint32_t tmp_sample = 0;
157+
if (sample != NULL) { tmp_sample = *sample; }
158+
159+
uint32_t flags = SAI_TxGetStatusFlag(obj->base);
160+
if ((flags & I2S_TCSR_TE_MASK) == 0) {
161+
SAI_TxEnable(obj->base, true);
162+
}
163+
if ((flags & I2S_TCSR_FEF_MASK) == I2S_TCSR_FEF_MASK) {
164+
SAI_TxClearStatusFlags(obj->base, I2S_TCSR_FEF_MASK);
165+
}
166+
ret = (flags & I2S_TCSR_FWF_MASK) == I2S_TCSR_FWF_MASK;
167+
if (ret) {
168+
SAI_WriteData(obj->base, obj->channel, tmp_sample);
169+
}
170+
}
171+
return ret;
172+
}
173+
174+
/** Releases & de-initialize the referenced peripherals. */
175+
void sai_free(sai_t *obj) {
176+
if (obj->is_receiver) {
177+
SAI_RxEnable(obj->base, false);
178+
} else {
179+
SAI_TxEnable(obj->base, false);
180+
}
181+
// Should it also unclock the periph ?
182+
}
183+
#endif

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/PeripheralPins.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
16+
1717
#ifndef MBED_PERIPHERALPINS_H
1818
#define MBED_PERIPHERALPINS_H
1919

@@ -47,4 +47,13 @@ extern const PinMap PinMap_SPI_SSEL[];
4747
/************PWM***************/
4848
extern const PinMap PinMap_PWM[];
4949

50+
/************I2S***************/
51+
extern const PinMap PinMap_SAI_MCLK[];
52+
extern const PinMap PinMap_SAI_TXSD[];
53+
extern const PinMap PinMap_SAI_TXBCLK[];
54+
extern const PinMap PinMap_SAI_TXWCLK[];
55+
extern const PinMap PinMap_SAI_RXSD[];
56+
extern const PinMap PinMap_SAI_RXBCLK[];
57+
extern const PinMap PinMap_SAI_RXWCLK[];
58+
5059
#endif

targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/api/objects.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ struct flash_s {
9595
flash_config_t flash_config;
9696
};
9797

98+
#ifdef DEVICE_SAI
99+
struct sai_s {
100+
I2S_Type *base;
101+
uint32_t channel;
102+
bool is_receiver;
103+
};
104+
#endif // DEVICE_SAI
105+
98106
#include "gpio_object.h"
99107

100108
#ifdef __cplusplus

targets/targets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@
697697
"macros": ["CPU_MK66FN2M0VMD18", "FSL_RTOS_MBED"],
698698
"inherits": ["Target"],
699699
"detect_code": ["0311"],
700-
"device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
700+
"device_has": ["SAI", "USTICKER", "LPTICKER", "RTC", "ANALOGIN", "ANALOGOUT", "EMAC", "I2C", "I2CSLAVE", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "STDIO_MESSAGES", "TRNG", "FLASH"],
701701
"features": ["LWIP"],
702702
"release_versions": ["2", "5"],
703703
"device_name": "MK66FN2M0xxx18",

0 commit comments

Comments
 (0)