Select one of the symbols to view example projects that use it.
 
Outline
#define _HARDWARE_INTERP_H
#include "pico.h"
#include "hardware/structs/interp.h"
#include "hardware/regs/sio.h"
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_INTERP
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_INTERP
#define interp0
#define interp1
interp_config
interp_index(interp_hw_t *)
interp_claim_lane(interp_hw_t *, uint);
#define interp_lane_claim
interp_claim_lane_mask(interp_hw_t *, uint);
interp_unclaim_lane(interp_hw_t *, uint);
#define interp_lane_unclaim
interp_lane_is_claimed(interp_hw_t *, uint);
interp_unclaim_lane_mask(interp_hw_t *, uint);
interp_config_set_shift(interp_config *, uint)
interp_config_set_mask(interp_config *, uint, uint)
interp_config_set_cross_input(interp_config *, bool)
interp_config_set_cross_result(interp_config *, bool)
interp_config_set_signed(interp_config *, bool)
interp_config_set_add_raw(interp_config *, bool)
interp_config_set_blend(interp_config *, bool)
interp_config_set_clamp(interp_config *, bool)
interp_config_set_force_bits(interp_config *, uint)
interp_default_config()
interp_set_config(interp_hw_t *, uint, interp_config *)
interp_set_force_bits(interp_hw_t *, uint, uint)
interp_hw_save_t
interp_save(interp_hw_t *, interp_hw_save_t *);
interp_restore(interp_hw_t *, interp_hw_save_t *);
interp_set_base(interp_hw_t *, uint, uint32_t)
interp_get_base(interp_hw_t *, uint)
interp_set_base_both(interp_hw_t *, uint32_t)
interp_set_accumulator(interp_hw_t *, uint, uint32_t)
interp_get_accumulator(interp_hw_t *, uint)
interp_pop_lane_result(interp_hw_t *, uint)
interp_peek_lane_result(interp_hw_t *, uint)
interp_pop_full_result(interp_hw_t *)
interp_peek_full_result(interp_hw_t *)
interp_add_accumulater(interp_hw_t *, uint, uint32_t)
interp_get_raw(interp_hw_t *, uint)
Files
loading...
SourceVuRaspberry Pi Pico SDK and ExamplesPicoSDKsrc/rp2_common/hardware_interp/include/hardware/interp.h
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause *//* ... */ #ifndef _HARDWARE_INTERP_H #define _HARDWARE_INTERP_H #include "pico.h" #include "hardware/structs/interp.h" #include "hardware/regs/sio.h" // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_INTERP, Enable/disable assertions in the hardware_interp module, type=bool, default=0, group=hardware_interp #ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_INTERP #ifdef PARAM_ASSERTIONS_ENABLED_INTERP // backwards compatibility with SDK < 2.0.0 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_INTERP PARAM_ASSERTIONS_ENABLED_INTERP #else #define PARAM_ASSERTIONS_ENABLED_HARDWARE_INTERP 0 #endif/* ... */ #endif #ifdef __cplusplus extern "C" { #endif /** \file hardware/interp.h * \defgroup hardware_interp hardware_interp * * \brief Hardware Interpolator API * * Each core is equipped with two interpolators (INTERP0 and INTERP1) which can be used to accelerate * tasks by combining certain pre-configured simple operations into a single processor cycle. Intended * for cases where the pre-configured operation is repeated a large number of times, this results in * code which uses both fewer CPU cycles and fewer CPU registers in the time critical sections of the * code. * * The interpolators are used heavily to accelerate audio operations within the SDK, but their * flexible configuration make it possible to optimise many other tasks such as quantization and * dithering, table lookup address generation, affine texture mapping, decompression and linear feedback. * * Please refer to the appropriate RP-series microcontroller datasheet for more information on the HW * interpolators and how they work. *//* ... */ #define interp0 interp0_hw #define interp1 interp1_hw /** \brief Interpolator configuration * \defgroup interp_config interp_config * \ingroup hardware_interp * * Each interpolator needs to be configured, these functions provide handy helpers to set up configuration * structures. * *//* ... */ typedef struct { uint32_t ctrl; ...} interp_config; static inline uint interp_index(interp_hw_t *interp) { valid_params_if(HARDWARE_INTERP, interp == interp0 || interp == interp1); return interp == interp1 ? 1 : 0; }{ ... } /*! \brief Claim the interpolator lane specified * \ingroup hardware_interp * * Use this function to claim exclusive access to the specified interpolator lane. * * This function will panic if the lane is already claimed. * * \param interp Interpolator on which to claim a lane. interp0 or interp1 * \param lane The lane number, 0 or 1. *//* ... */ void interp_claim_lane(interp_hw_t *interp, uint lane); // The above really should be called this for consistency #define interp_lane_claim interp_claim_lane /*! \brief Claim the interpolator lanes specified in the mask * \ingroup hardware_interp * * \param interp Interpolator on which to claim lanes. interp0 or interp1 * \param lane_mask Bit pattern of lanes to claim (only bits 0 and 1 are valid) *//* ... */ void interp_claim_lane_mask(interp_hw_t *interp, uint lane_mask); /*! \brief Release a previously claimed interpolator lane * \ingroup hardware_interp * * \param interp Interpolator on which to release a lane. interp0 or interp1 * \param lane The lane number, 0 or 1 *//* ... */ void interp_unclaim_lane(interp_hw_t *interp, uint lane); // The above really should be called this for consistency #define interp_lane_unclaim interp_unclaim_lane /*! \brief Determine if an interpolator lane is claimed * \ingroup hardware_interp * * \param interp Interpolator whose lane to check * \param lane The lane number, 0 or 1 * \return true if claimed, false otherwise * \see interp_claim_lane * \see interp_claim_lane_mask *//* ... */ bool interp_lane_is_claimed(interp_hw_t *interp, uint lane); /*! \brief Release previously claimed interpolator lanes \see interp_claim_lane_mask * \ingroup hardware_interp * * \param interp Interpolator on which to release lanes. interp0 or interp1 * \param lane_mask Bit pattern of lanes to unclaim (only bits 0 and 1 are valid) *//* ... */ void interp_unclaim_lane_mask(interp_hw_t *interp, uint lane_mask); /*! \brief Set the interpolator shift value * \ingroup interp_config * * Sets the number of bits the accumulator is shifted before masking, on each iteration. * * \param c Pointer to an interpolator config * \param shift Number of bits *//* ... */ static inline void interp_config_set_shift(interp_config *c, uint shift) { valid_params_if(HARDWARE_INTERP, shift < 32); c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_SHIFT_BITS) | ((shift << SIO_INTERP0_CTRL_LANE0_SHIFT_LSB) & SIO_INTERP0_CTRL_LANE0_SHIFT_BITS); }{ ... } /*! \brief Set the interpolator mask range * \ingroup interp_config * * Sets the range of bits (least to most) that are allowed to pass through the interpolator * * \param c Pointer to interpolation config * \param mask_lsb The least significant bit allowed to pass * \param mask_msb The most significant bit allowed to pass *//* ... */ static inline void interp_config_set_mask(interp_config *c, uint mask_lsb, uint mask_msb) { valid_params_if(HARDWARE_INTERP, mask_msb < 32); valid_params_if(HARDWARE_INTERP, mask_lsb <= mask_msb); c->ctrl = (c->ctrl & ~(SIO_INTERP0_CTRL_LANE0_MASK_LSB_BITS | SIO_INTERP0_CTRL_LANE0_MASK_MSB_BITS)) | ((mask_lsb << SIO_INTERP0_CTRL_LANE0_MASK_LSB_LSB) & SIO_INTERP0_CTRL_LANE0_MASK_LSB_BITS) | ((mask_msb << SIO_INTERP0_CTRL_LANE0_MASK_MSB_LSB) & SIO_INTERP0_CTRL_LANE0_MASK_MSB_BITS); }{ ... } /*! \brief Enable cross input * \ingroup interp_config * * Allows feeding of the accumulator content from the other lane back in to this lanes shift+mask hardware. * This will take effect even if the interp_config_set_add_raw option is set as the cross input mux is before the * shift+mask bypass * * \param c Pointer to interpolation config * \param cross_input If true, enable the cross input. *//* ... */ static inline void interp_config_set_cross_input(interp_config *c, bool cross_input) { c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_CROSS_INPUT_BITS) | (cross_input ? SIO_INTERP0_CTRL_LANE0_CROSS_INPUT_BITS : 0); }{ ... } /*! \brief Enable cross results * \ingroup interp_config * * Allows feeding of the other lane’s result into this lane’s accumulator on a POP operation. * * \param c Pointer to interpolation config * \param cross_result If true, enables the cross result *//* ... */ static inline void interp_config_set_cross_result(interp_config *c, bool cross_result) { c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_CROSS_RESULT_BITS) | (cross_result ? SIO_INTERP0_CTRL_LANE0_CROSS_RESULT_BITS : 0); }{ ... } /*! \brief Set sign extension * \ingroup interp_config * * Enables signed mode, where the shifted and masked accumulator value is sign-extended to 32 bits * before adding to BASE1, and LANE1 PEEK/POP results appear extended to 32 bits when read by processor. * * \param c Pointer to interpolation config * \param _signed If true, enables sign extension *//* ... */ static inline void interp_config_set_signed(interp_config *c, bool _signed) { c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_SIGNED_BITS) | (_signed ? SIO_INTERP0_CTRL_LANE0_SIGNED_BITS : 0); }{ ... } /*! \brief Set raw add option * \ingroup interp_config * * When enabled, mask + shift is bypassed for LANE0 result. This does not affect the FULL result. * * \param c Pointer to interpolation config * \param add_raw If true, enable raw add option. *//* ... */ static inline void interp_config_set_add_raw(interp_config *c, bool add_raw) { c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_ADD_RAW_BITS) | (add_raw ? SIO_INTERP0_CTRL_LANE0_ADD_RAW_BITS : 0); }{ ... } /*! \brief Set blend mode * \ingroup interp_config * * If enabled, LANE1 result is a linear interpolation between BASE0 and BASE1, controlled * by the 8 LSBs of lane 1 shift and mask value (a fractional number between 0 and 255/256ths) * * LANE0 result does not have BASE0 added (yields only the 8 LSBs of lane 1 shift+mask value) * * FULL result does not have lane 1 shift+mask value added (BASE2 + lane 0 shift+mask) * * LANE1 SIGNED flag controls whether the interpolation is signed or unsig * * \param c Pointer to interpolation config * \param blend Set true to enable blend mode. *//* ... */ static inline void interp_config_set_blend(interp_config *c, bool blend) { c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_BLEND_BITS) | (blend ? SIO_INTERP0_CTRL_LANE0_BLEND_BITS : 0); }{ ... } /*! \brief Set interpolator clamp mode (Interpolator 1 only) * \ingroup interp_config * * Only present on INTERP1 on each core. If CLAMP mode is enabled: * - LANE0 result is a shifted and masked ACCUM0, clamped by a lower bound of BASE0 and an upper bound of BASE1. * - Signedness of these comparisons is determined by LANE0_CTRL_SIGNED * * \param c Pointer to interpolation config * \param clamp Set true to enable clamp mode *//* ... */ static inline void interp_config_set_clamp(interp_config *c, bool clamp) { c->ctrl = (c->ctrl & ~SIO_INTERP1_CTRL_LANE0_CLAMP_BITS) | (clamp ? SIO_INTERP1_CTRL_LANE0_CLAMP_BITS : 0); }{ ... } /*! \brief Set interpolator Force bits * \ingroup interp_config * * ORed into bits 29:28 of the lane result presented to the processor on the bus. * * No effect on the internal 32-bit datapath. Handy for using a lane to generate sequence * of pointers into flash or SRAM * * \param c Pointer to interpolation config * \param bits Sets the force bits to that specified. Range 0-3 (two bits) *//* ... */ static inline void interp_config_set_force_bits(interp_config *c, uint bits) { invalid_params_if(HARDWARE_INTERP, bits > 3); // note cannot use hw_set_bits on SIO c->ctrl = (c->ctrl & ~SIO_INTERP0_CTRL_LANE0_FORCE_MSB_BITS) | (bits << SIO_INTERP0_CTRL_LANE0_FORCE_MSB_LSB); }{ ... } /*! \brief Get a default configuration * \ingroup interp_config * * \return A default interpolation configuration *//* ... */ static inline interp_config interp_default_config(void) { interp_config c = {0}; // Just pass through everything interp_config_set_mask(&c, 0, 31); return c; }{ ... } /*! \brief Send configuration to a lane * \ingroup interp_config * * If an invalid configuration is specified (ie a lane specific item is set on wrong lane), * depending on setup this function can panic. * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane to set * \param config Pointer to interpolation config *//* ... */ static inline void interp_set_config(interp_hw_t *interp, uint lane, interp_config *config) { invalid_params_if(HARDWARE_INTERP, lane > 1); invalid_params_if(HARDWARE_INTERP, config->ctrl & SIO_INTERP1_CTRL_LANE0_CLAMP_BITS && (!interp_index(interp) || lane)); // only interp1 lane 0 has clamp bit invalid_params_if(HARDWARE_INTERP, config->ctrl & SIO_INTERP0_CTRL_LANE0_BLEND_BITS && (interp_index(interp) || lane)); // only interp0 lane 0 has blend bit interp->ctrl[lane] = config->ctrl; }{ ... } /*! \brief Directly set the force bits on a specified lane * \ingroup hardware_interp * * These bits are ORed into bits 29:28 of the lane result presented to the processor on the bus. * There is no effect on the internal 32-bit datapath. * * Useful for using a lane to generate sequence of pointers into flash or SRAM, saving a subsequent * OR or add operation. * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane to set * \param bits The bits to set (bits 0 and 1, value range 0-3) *//* ... */ static inline void interp_set_force_bits(interp_hw_t *interp, uint lane, uint bits) { // note cannot use hw_set_bits on SIO interp->ctrl[lane] = interp->ctrl[lane] | (bits << SIO_INTERP0_CTRL_LANE0_FORCE_MSB_LSB); }{ ... } typedef struct { uint32_t accum[2]; uint32_t base[3]; uint32_t ctrl[2]; ...} interp_hw_save_t; /*! \brief Save the specified interpolator state * \ingroup hardware_interp * * Can be used to save state if you need an interpolator for another purpose, state * can then be recovered afterwards and continue from that point * * \param interp Interpolator instance, interp0 or interp1. * \param saver Pointer to the save structure to fill in *//* ... */ void interp_save(interp_hw_t *interp, interp_hw_save_t *saver); /*! \brief Restore an interpolator state * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param saver Pointer to save structure to reapply to the specified interpolator *//* ... */ void interp_restore(interp_hw_t *interp, interp_hw_save_t *saver); /*! \brief Sets the interpolator base register by lane * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 or 2 * \param val The value to apply to the register *//* ... */ static inline void interp_set_base(interp_hw_t *interp, uint lane, uint32_t val) { interp->base[lane] = val; }{ ... } /*! \brief Gets the content of interpolator base register by lane * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 or 2 * \return The current content of the lane base register *//* ... */ static inline uint32_t interp_get_base(interp_hw_t *interp, uint lane) { return interp->base[lane]; }{ ... } /*! \brief Sets the interpolator base registers simultaneously * \ingroup hardware_interp * * The lower 16 bits go to BASE0, upper bits to BASE1 simultaneously. * Each half is sign-extended to 32 bits if that lane’s SIGNED flag is set. * * \param interp Interpolator instance, interp0 or interp1. * \param val The value to apply to the register *//* ... */ static inline void interp_set_base_both(interp_hw_t *interp, uint32_t val) { interp->base01 = val; }{ ... } /*! \brief Sets the interpolator accumulator register by lane * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 * \param val The value to apply to the register *//* ... */ static inline void interp_set_accumulator(interp_hw_t *interp, uint lane, uint32_t val) { interp->accum[lane] = val; }{ ... } /*! \brief Gets the content of the interpolator accumulator register by lane * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 * \return The current content of the register *//* ... */ static inline uint32_t interp_get_accumulator(interp_hw_t *interp, uint lane) { return interp->accum[lane]; }{ ... } /*! \brief Read lane result, and write lane results to both accumulators to update the interpolator * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 * \return The content of the lane result register *//* ... */ static inline uint32_t interp_pop_lane_result(interp_hw_t *interp, uint lane) { return interp->pop[lane]; }{ ... } /*! \brief Read lane result * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 * \return The content of the lane result register *//* ... */ static inline uint32_t interp_peek_lane_result(interp_hw_t *interp, uint lane) { return interp->peek[lane]; }{ ... } /*! \brief Read lane result, and write lane results to both accumulators to update the interpolator * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \return The content of the FULL register *//* ... */ static inline uint32_t interp_pop_full_result(interp_hw_t *interp) { return interp->pop[2]; }{ ... } /*! \brief Read lane result * \ingroup hardware_interp * * \param interp Interpolator instance, interp0 or interp1. * \return The content of the FULL register *//* ... */ static inline uint32_t interp_peek_full_result(interp_hw_t *interp) { return interp->peek[2]; }{ ... } /*! \brief Add to accumulator * \ingroup hardware_interp * * Atomically add the specified value to the accumulator on the specified lane * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 * \param val Value to add *//* ... */ static inline void interp_add_accumulater(interp_hw_t *interp, uint lane, uint32_t val) { interp->add_raw[lane] = val; }{ ... } /*! \brief Get raw lane value * \ingroup hardware_interp * * Returns the raw shift and mask value from the specified lane, BASE0 is NOT added * * \param interp Interpolator instance, interp0 or interp1. * \param lane The lane number, 0 or 1 * \return The raw shift/mask value *//* ... */ static inline uint32_t interp_get_raw(interp_hw_t *interp, uint lane) { return interp->add_raw[lane]; }{ ... } #ifdef __cplusplus }extern "C" { ... } #endif /* ... */ #endif
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.