annotate pru_rtaudio.p @ 21:0d80ff9e2227

Add float<->int macros to PRU code (still to integrate); formatting cleanups
author andrewm
date Sun, 08 Feb 2015 00:20:01 +0000
parents 6adb088196a7
children 472e892c6e41
rev   line source
andrewm@0 1 .origin 0
andrewm@0 2 .entrypoint START
andrewm@0 3
andrewm@0 4 #define DBOX_CAPE // Define this to use new cape hardware
andrewm@0 5
andrewm@0 6 #define CLOCK_BASE 0x44E00000
andrewm@0 7 #define CLOCK_SPI0 0x4C
andrewm@0 8 #define CLOCK_SPI1 0x50
andrewm@0 9 #define CLOCK_L4LS 0x60
andrewm@0 10
andrewm@0 11 #define SPI0_BASE 0x48030100
andrewm@0 12 #define SPI1_BASE 0x481A0100
andrewm@0 13 #define SPI_BASE SPI0_BASE
andrewm@0 14
andrewm@0 15 #define SPI_SYSCONFIG 0x10
andrewm@0 16 #define SPI_SYSSTATUS 0x14
andrewm@0 17 #define SPI_MODULCTRL 0x28
andrewm@0 18 #define SPI_CH0CONF 0x2C
andrewm@0 19 #define SPI_CH0STAT 0x30
andrewm@0 20 #define SPI_CH0CTRL 0x34
andrewm@0 21 #define SPI_CH0TX 0x38
andrewm@0 22 #define SPI_CH0RX 0x3C
andrewm@0 23 #define SPI_CH1CONF 0x40
andrewm@0 24 #define SPI_CH1STAT 0x44
andrewm@0 25 #define SPI_CH1CTRL 0x48
andrewm@0 26 #define SPI_CH1TX 0x4C
andrewm@0 27 #define SPI_CH1RX 0x50
andrewm@0 28
andrewm@0 29 #define GPIO0 0x44E07000
andrewm@0 30 #define GPIO1 0x4804C000
andrewm@0 31 #define GPIO_CLEARDATAOUT 0x190
andrewm@0 32 #define GPIO_SETDATAOUT 0x194
andrewm@0 33
andrewm@0 34 #define PRU0_ARM_INTERRUPT 19
andrewm@0 35
andrewm@0 36 #define C_ADC_DAC_MEM C24 // PRU0 mem
andrewm@0 37 #ifdef DBOX_CAPE
andrewm@0 38 #define DAC_GPIO GPIO0
andrewm@0 39 #define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17
andrewm@0 40 #else
andrewm@0 41 #define DAC_GPIO GPIO1
andrewm@0 42 #define DAC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15
andrewm@0 43 #endif
andrewm@0 44 #define DAC_TRM 0 // SPI transmit and receive
andrewm@0 45 #define DAC_WL 32 // Word length
andrewm@0 46 #define DAC_CLK_MODE 1 // SPI mode
andrewm@0 47 #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n)
andrewm@0 48 #define DAC_DPE 1 // d0 = receive, d1 = transmit
andrewm@0 49
andrewm@0 50 #define AD5668_COMMAND_OFFSET 24
andrewm@0 51 #define AD5668_ADDRESS_OFFSET 20
andrewm@0 52 #define AD5668_DATA_OFFSET 4
andrewm@0 53 #define AD5668_REF_OFFSET 0
andrewm@0 54
andrewm@0 55 #ifdef DBOX_CAPE
andrewm@0 56 #define ADC_GPIO GPIO1
andrewm@0 57 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15
andrewm@0 58 #else
andrewm@0 59 #define ADC_GPIO GPIO1
andrewm@0 60 #define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23
andrewm@0 61 #endif
andrewm@0 62 #define ADC_TRM 0 // SPI transmit and receive
andrewm@0 63 #define ADC_WL 16 // Word length
andrewm@0 64 #define ADC_CLK_MODE 0 // SPI mode
andrewm@0 65 #define ADC_CLK_DIV 1 // Clock divider (48MHz / 2^n)
andrewm@0 66 #define ADC_DPE 1 // d0 = receive, d1 = transmit
andrewm@0 67
andrewm@0 68 #define AD7699_CFG_MASK 0xF120 // Mask for config update, unipolar, full BW
andrewm@0 69 #define AD7699_CHANNEL_OFFSET 9 // 7 bits offset of a 14-bit left-justified word
andrewm@0 70 #define AD7699_SEQ_OFFSET 3 // sequencer (0 = disable, 3 = scan all)
andrewm@0 71
andrewm@0 72 #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written
andrewm@0 73 #define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop
andrewm@0 74 #define COMM_CURRENT_BUFFER 4 // Which buffer we are on
andrewm@0 75 #define COMM_BUFFER_FRAMES 8 // How many frames per buffer
andrewm@0 76 #define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock
andrewm@0 77 #define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on
andrewm@0 78 #define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync
andrewm@0 79 #define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on
andrewm@0 80 #define COMM_LED_PIN_MASK 28 // Which pin to write to change LED
andrewm@0 81 #define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning
andrewm@0 82 #define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC
andrewm@12 83 #define COMM_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels
andrewm@0 84
andrewm@0 85 #define MCASP0_BASE 0x48038000
andrewm@0 86 #define MCASP1_BASE 0x4803C000
andrewm@0 87
andrewm@0 88 #define MCASP_PWRIDLESYSCONFIG 0x04
andrewm@0 89 #define MCASP_PFUNC 0x10
andrewm@0 90 #define MCASP_PDIR 0x14
andrewm@0 91 #define MCASP_PDOUT 0x18
andrewm@0 92 #define MCASP_PDSET 0x1C
andrewm@0 93 #define MCASP_PDIN 0x1C
andrewm@0 94 #define MCASP_PDCLR 0x20
andrewm@0 95 #define MCASP_GBLCTL 0x44
andrewm@0 96 #define MCASP_AMUTE 0x48
andrewm@0 97 #define MCASP_DLBCTL 0x4C
andrewm@0 98 #define MCASP_DITCTL 0x50
andrewm@0 99 #define MCASP_RGBLCTL 0x60
andrewm@0 100 #define MCASP_RMASK 0x64
andrewm@0 101 #define MCASP_RFMT 0x68
andrewm@0 102 #define MCASP_AFSRCTL 0x6C
andrewm@0 103 #define MCASP_ACLKRCTL 0x70
andrewm@0 104 #define MCASP_AHCLKRCTL 0x74
andrewm@0 105 #define MCASP_RTDM 0x78
andrewm@0 106 #define MCASP_RINTCTL 0x7C
andrewm@0 107 #define MCASP_RSTAT 0x80
andrewm@0 108 #define MCASP_RSLOT 0x84
andrewm@0 109 #define MCASP_RCLKCHK 0x88
andrewm@0 110 #define MCASP_REVTCTL 0x8C
andrewm@0 111 #define MCASP_XGBLCTL 0xA0
andrewm@0 112 #define MCASP_XMASK 0xA4
andrewm@0 113 #define MCASP_XFMT 0xA8
andrewm@0 114 #define MCASP_AFSXCTL 0xAC
andrewm@0 115 #define MCASP_ACLKXCTL 0xB0
andrewm@0 116 #define MCASP_AHCLKXCTL 0xB4
andrewm@0 117 #define MCASP_XTDM 0xB8
andrewm@0 118 #define MCASP_XINTCTL 0xBC
andrewm@0 119 #define MCASP_XSTAT 0xC0
andrewm@0 120 #define MCASP_XSLOT 0xC4
andrewm@0 121 #define MCASP_XCLKCHK 0xC8
andrewm@0 122 #define MCASP_XEVTCTL 0xCC
andrewm@0 123 #define MCASP_SRCTL0 0x180
andrewm@0 124 #define MCASP_SRCTL1 0x184
andrewm@0 125 #define MCASP_SRCTL2 0x188
andrewm@0 126 #define MCASP_SRCTL3 0x18C
andrewm@0 127 #define MCASP_SRCTL4 0x190
andrewm@0 128 #define MCASP_SRCTL5 0x194
andrewm@0 129 #define MCASP_XBUF0 0x200
andrewm@0 130 #define MCASP_XBUF1 0x204
andrewm@0 131 #define MCASP_XBUF2 0x208
andrewm@0 132 #define MCASP_XBUF3 0x20C
andrewm@0 133 #define MCASP_XBUF4 0x210
andrewm@0 134 #define MCASP_XBUF5 0x214
andrewm@0 135 #define MCASP_RBUF0 0x280
andrewm@0 136 #define MCASP_RBUF1 0x284
andrewm@0 137 #define MCASP_RBUF2 0x288
andrewm@0 138 #define MCASP_RBUF3 0x28C
andrewm@0 139 #define MCASP_RBUF4 0x290
andrewm@0 140 #define MCASP_RBUF5 0x294
andrewm@0 141 #define MCASP_WFIFOCTL 0x1000
andrewm@0 142 #define MCASP_WFIFOSTS 0x1004
andrewm@0 143 #define MCASP_RFIFOCTL 0x1008
andrewm@0 144 #define MCASP_RFIFOSTS 0x100C
andrewm@0 145
andrewm@0 146 #define MCASP_XSTAT_XDATA_BIT 5 // Bit to test for transmit ready
andrewm@0 147 #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready
andrewm@0 148
andrewm@0 149 // Constants used for this particular audio setup
andrewm@0 150 #define MCASP_BASE MCASP0_BASE
andrewm@0 151 #ifdef DBOX_CAPE
andrewm@0 152 #define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter
andrewm@0 153 #define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver
andrewm@0 154 #define MCASP_XBUF MCASP_XBUF2
andrewm@0 155 #define MCASP_RBUF MCASP_RBUF0
andrewm@0 156 #else
andrewm@0 157 #define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter
andrewm@0 158 #define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver
andrewm@0 159 #define MCASP_XBUF MCASP_XBUF3
andrewm@0 160 #define MCASP_RBUF MCASP_RBUF2
andrewm@0 161 #endif
andrewm@0 162
andrewm@0 163 #define MCASP_PIN_AFSX (1 << 28)
andrewm@0 164 #define MCASP_PIN_AHCLKX (1 << 27)
andrewm@0 165 #define MCASP_PIN_ACLKX (1 << 26)
andrewm@0 166 #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3
andrewm@0 167
andrewm@0 168 #ifdef DBOX_CAPE
andrewm@0 169 #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs
andrewm@0 170 #else
andrewm@0 171 #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs
andrewm@0 172 #endif
andrewm@0 173
andrewm@0 174 #define MCASP_DATA_MASK 0xFFFF // 16 bit data
andrewm@0 175 #define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits
andrewm@0 176
andrewm@12 177 #define C_MCASP_MEM C28 // Shared PRU mem
andrewm@0 178
andrewm@0 179 // Flags for the flags register
andrewm@0 180 #define FLAG_BIT_BUFFER1 0
andrewm@0 181 #define FLAG_BIT_USE_SPI 1
andrewm@12 182 #define FLAG_BIT_MCASP_HWORD 2 // Whether we are on the high word for McASP transmission
andrewm@0 183
andrewm@0 184 // Registers used throughout
andrewm@0 185
andrewm@0 186 // r1, r2, r3 are used for temporary storage
andrewm@12 187 #define reg_num_channels r9 // Number of SPI ADC/DAC channels to use
andrewm@0 188 #define reg_frame_current r10 // Current frame count in SPI ADC/DAC transfer
andrewm@0 189 #define reg_frame_total r11 // Total frame count for SPI ADC/DAC
andrewm@0 190 #define reg_dac_data r12 // Current dword for SPI DAC
andrewm@0 191 #define reg_adc_data r13 // Current dword for SPI ADC
andrewm@0 192 #define reg_mcasp_dac_data r14 // Current dword for McASP DAC
andrewm@0 193 #define reg_mcasp_adc_data r15 // Current dword for McASP ADC
andrewm@0 194 #define reg_dac_buf0 r16 // Start pointer to SPI DAC buffer 0
andrewm@0 195 #define reg_dac_buf1 r17 // Start pointer to SPI DAC buffer 1
andrewm@0 196 #define reg_dac_current r18 // Pointer to current storage location of SPI DAC
andrewm@0 197 #define reg_adc_current r19 // Pointer to current storage location of SPI ADC
andrewm@0 198 #define reg_mcasp_buf0 r20 // Start pointer to McASP DAC buffer 0
andrewm@0 199 #define reg_mcasp_buf1 r21 // Start pointer to McASP DAC buffer 1
andrewm@0 200 #define reg_mcasp_dac_current r22 // Pointer to current storage location of McASP DAC
andrewm@0 201 #define reg_mcasp_adc_current r23 // Pointer to current storage location of McASP ADC
andrewm@0 202 #define reg_flags r24 // Buffer ID (0 and 1) and other flags
andrewm@0 203 #define reg_comm_addr r25 // Memory address for communicating with ARM
andrewm@0 204 #define reg_spi_addr r26 // Base address for SPI
andrewm@0 205 // r27, r28 used in macros
andrewm@0 206 #define reg_mcasp_addr r29 // Base address for McASP
andrewm@0 207
andrewm@21 208 // Convert float to 16-bit int, multiplying by 32768
andrewm@21 209 // Converts -1.0 to 1.0 to a full 16-bit range
andrewm@21 210 // input and output can safely be the same register
andrewm@21 211 .macro FLOAT_TO_INT16
andrewm@21 212 .mparam input, output
andrewm@21 213 // int exponent = ((input >> 23) & 0xFF)
andrewm@21 214 LSR r27, input, 23 // exponent goes in r27
andrewm@21 215 AND r27, r27, 0xFF
andrewm@21 216
andrewm@21 217 // Actual exponent is 127 less than the above; below -15 we
andrewm@21 218 // should return 0. So check if it is less than 112.
andrewm@21 219 QBLE EXPONENT_GREQ_MINUS15, r27, 112
andrewm@21 220 LDI output, 0
andrewm@21 221 QBA FLOAT_TO_INT16_DONE
andrewm@21 222 EXPONENT_GREQ_MINUS15:
andrewm@21 223
andrewm@21 224 // Next check if exponent is greater than or equal to 0 (i.e.
andrewm@21 225 // 127 in our adjusted version. If so we return the max.
andrewm@21 226 QBGT EXPONENT_LT_ZERO, r27, 127
andrewm@21 227 QBBS NEGATIVE_MAX, input, 31 // Is sign negative?
andrewm@21 228 LDI output, 32767 // Max positive value
andrewm@21 229 QBA FLOAT_TO_INT16_DONE
andrewm@21 230 NEGATIVE_MAX:
andrewm@21 231 LDI output, 32768 // Actually will be -32768 in signed
andrewm@21 232 QBA FLOAT_TO_INT16_DONE
andrewm@21 233 EXPONENT_LT_ZERO:
andrewm@21 234
andrewm@21 235 // Mask out the mantissa and shift
andrewm@21 236 // int mantissa = (input & 0x7FFFFF) | (1 << 23)
andrewm@21 237 MOV r28, 0x007FFFFF
andrewm@21 238 AND r28, r28, input
andrewm@21 239 SET r28, 23
andrewm@21 240
andrewm@21 241 // Shift right by -(exponent - 127 - 8) to produce an int
andrewm@21 242 // after effectively multiplying by 2^15
andrewm@21 243 // ---> (135 - exponent)
andrewm@21 244 RSB r27, r27, 135
andrewm@21 245 LSR r28, r28, r27
andrewm@21 246
andrewm@21 247 // Finally, check the sign bit and invert if needed
andrewm@21 248 QBBS NEGATIVE_RESULT, input, 31
andrewm@21 249 // Positive result: but might be 32768 so needs checking
andrewm@21 250 LDI r27, 0x7FFF
andrewm@21 251 MIN output, r27, r28
andrewm@21 252 QBA FLOAT_TO_INT16_DONE
andrewm@21 253 NEGATIVE_RESULT:
andrewm@21 254 // Take negative: invert the bits and add 1
andrewm@21 255 LDI r27, 0xFFFF
andrewm@21 256 XOR r28, r28, r27
andrewm@21 257 ADD r28, r28, 1
andrewm@21 258 CLR output, r28, 16 // Clear carry bit if present
andrewm@21 259 FLOAT_TO_INT16_DONE:
andrewm@21 260 .endm
andrewm@21 261
andrewm@21 262
andrewm@21 263 // Convert float to 16-bit unsigned int, multiplying by 65536
andrewm@21 264 // Converts 0.0 to 1.0 to a full 16-bit range
andrewm@21 265 // input and output can safely be the same register
andrewm@21 266 .macro FLOAT_TO_UINT16
andrewm@21 267 .mparam input, output
andrewm@21 268 QBBC NONNEGATIVE, input, 31 // Is sign negative?
andrewm@21 269 LDI output, 0 // All < 0 inputs produce 0 output
andrewm@21 270 QBA FLOAT_TO_UINT16_DONE
andrewm@21 271 NONNEGATIVE:
andrewm@21 272 // int exponent = ((input >> 23) & 0xFF)
andrewm@21 273 LSR r27, input, 23 // exponent goes in r27
andrewm@21 274 AND r27, r27, 0xFF
andrewm@21 275
andrewm@21 276 // Actual exponent is 127 less than the above; below -16 we
andrewm@21 277 // should return 0. So check if it is less than 111.
andrewm@21 278 QBLE EXPONENT_GREQ_MINUS16, r27, 111
andrewm@21 279 LDI output, 0
andrewm@21 280 QBA FLOAT_TO_UINT16_DONE
andrewm@21 281 EXPONENT_GREQ_MINUS16:
andrewm@21 282
andrewm@21 283 // Next check if exponent is greater than or equal to 0 (i.e.
andrewm@21 284 // 127 in our adjusted version. If so we return the max.
andrewm@21 285 QBGT EXPONENT_LT_ZERO, r27, 127
andrewm@21 286 LDI output, 65535 // Max positive value
andrewm@21 287 QBA FLOAT_TO_UINT16_DONE
andrewm@21 288 EXPONENT_LT_ZERO:
andrewm@21 289
andrewm@21 290 // Mask out the mantissa and shift
andrewm@21 291 // int mantissa = (input & 0x7FFFFF) | (1 << 23)
andrewm@21 292 MOV r28, 0x007FFFFF
andrewm@21 293 AND r28, r28, input
andrewm@21 294 SET r28, 23
andrewm@21 295
andrewm@21 296 // Shift right by -(exponent - 127 - 7) to produce an int
andrewm@21 297 // after effectively multiplying by 2^16
andrewm@21 298 // ---> (134 - exponent)
andrewm@21 299 RSB r27, r27, 134
andrewm@21 300 LSR r28, r28, r27
andrewm@21 301
andrewm@21 302 // Check for 65536 and clip at 65535
andrewm@21 303 LDI r27, 0xFFFF
andrewm@21 304 MIN output, r27, r28
andrewm@21 305 FLOAT_TO_UINT16_DONE:
andrewm@21 306 .endm
andrewm@21 307
andrewm@21 308
andrewm@21 309 // Convert a 16-bit int to float. This macro assumes that the upper
andrewm@21 310 // 16 bits of input are 0 and may behave strangely if this is not the case.
andrewm@21 311 // input and output must be different registers
andrewm@21 312 .macro INT16_TO_FLOAT
andrewm@21 313 .mparam input, output
andrewm@21 314 // Check edge cases first: 0 and -32768 (= 32768 in unsigned)
andrewm@21 315 QBNE INPUT_NOT_ZERO, input, 0
andrewm@21 316 LDI output, 0
andrewm@21 317 QBA INT16_TO_FLOAT_DONE
andrewm@21 318 INPUT_NOT_ZERO:
andrewm@21 319 LDI r28, 32768
andrewm@21 320 QBNE INPUT_NOT_MIN, input, r28
andrewm@21 321 MOV output, 0xBF800000 // -1.0
andrewm@21 322 QBA INT16_TO_FLOAT_DONE
andrewm@21 323 INPUT_NOT_MIN:
andrewm@21 324 // Check for negative values = values with bit 15 set
andrewm@21 325 MOV output, input
andrewm@21 326 QBBC NEGATIVE_DONE, output, 15
andrewm@21 327 LDI r28, 0xFFFF
andrewm@21 328 XOR output, output, r28
andrewm@21 329 ADD output, output, 1
andrewm@21 330 CLR output, 16 // Clear any carry bit
andrewm@21 331 NEGATIVE_DONE:
andrewm@21 332 // Now we need to find the highest bit that is 1 in order to determine
andrewm@21 333 // the exponent
andrewm@21 334 LMBD r28, output, 1
andrewm@21 335
andrewm@21 336 // Calculate exponent field: 127 + 8 + (r28 - 23) = 112 + r28
andrewm@21 337 ADD r27, r28, 112
andrewm@21 338
andrewm@21 339 // Take 23 minus the result to get the shift
andrewm@21 340 RSB r28, r28, 23
andrewm@21 341 LSL output, output, r28
andrewm@21 342
andrewm@21 343 // Now clear bit 23 (implicitly 1) and replace it with the exponent
andrewm@21 344 CLR output, output, 23
andrewm@21 345 LSL r27, r27, 23
andrewm@21 346 OR output, output, r27
andrewm@21 347
andrewm@21 348 // Put the sign bit back in place
andrewm@21 349 QBBC INT16_TO_FLOAT_DONE, input, 15
andrewm@21 350 SET output, 31
andrewm@21 351 INT16_TO_FLOAT_DONE:
andrewm@21 352 .endm
andrewm@21 353
andrewm@21 354 // Convert a 16-bit unsigned int to float.
andrewm@21 355 .macro UINT16_TO_FLOAT
andrewm@21 356 .mparam input, output
andrewm@21 357 MOV output, input
andrewm@21 358
andrewm@21 359 // Clear upper 16 bits
andrewm@21 360 LDI r27, 0xFFFF
andrewm@21 361 AND output, output, r27
andrewm@21 362
andrewm@21 363 // If zero, we're done
andrewm@21 364 QBEQ UINT16_TO_FLOAT_DONE, output, 0
andrewm@21 365
andrewm@21 366 // Now we need to find the highest bit that is 1 in order to determine
andrewm@21 367 // the exponent
andrewm@21 368 LMBD r28, output, 1
andrewm@21 369
andrewm@21 370 // Calculate exponent field: 127 + 7 + (r28 - 23) = 111 + r28
andrewm@21 371 ADD r27, r28, 111
andrewm@21 372
andrewm@21 373 // Take 23 minus the result to get the shift
andrewm@21 374 RSB r28, r28, 23
andrewm@21 375 LSL output, output, r28
andrewm@21 376
andrewm@21 377 // Now clear bit 23 (implicitly 1) and replace it with the exponent
andrewm@21 378 CLR output, output, 23
andrewm@21 379 LSL r27, r27, 23
andrewm@21 380 OR output, output, r27
andrewm@21 381 UINT16_TO_FLOAT_DONE:
andrewm@21 382 .endm
andrewm@0 383
andrewm@0 384 // Bring CS line low to write to DAC
andrewm@0 385 .macro DAC_CS_ASSERT
andrewm@0 386 MOV r27, DAC_CS_PIN
andrewm@0 387 MOV r28, DAC_GPIO + GPIO_CLEARDATAOUT
andrewm@0 388 SBBO r27, r28, 0, 4
andrewm@0 389 .endm
andrewm@0 390
andrewm@0 391 // Bring CS line high at end of DAC transaction
andrewm@0 392 .macro DAC_CS_UNASSERT
andrewm@0 393 MOV r27, DAC_CS_PIN
andrewm@0 394 MOV r28, DAC_GPIO + GPIO_SETDATAOUT
andrewm@0 395 SBBO r27, r28, 0, 4
andrewm@0 396 .endm
andrewm@0 397
andrewm@0 398 // Write to DAC TX register
andrewm@0 399 .macro DAC_TX
andrewm@0 400 .mparam data
andrewm@0 401 SBBO data, reg_spi_addr, SPI_CH0TX, 4
andrewm@0 402 .endm
andrewm@0 403
andrewm@0 404 // Wait for SPI to finish (uses RXS indicator)
andrewm@0 405 .macro DAC_WAIT_FOR_FINISH
andrewm@0 406 LOOP:
andrewm@0 407 LBBO r27, reg_spi_addr, SPI_CH0STAT, 4
andrewm@0 408 QBBC LOOP, r27, 0
andrewm@0 409 .endm
andrewm@0 410
andrewm@0 411 // Read the RX word to clear
andrewm@0 412 .macro DAC_DISCARD_RX
andrewm@0 413 LBBO r27, reg_spi_addr, SPI_CH0RX, 4
andrewm@0 414 .endm
andrewm@0 415
andrewm@0 416 // Complete DAC write with chip select
andrewm@0 417 .macro DAC_WRITE
andrewm@0 418 .mparam reg
andrewm@0 419 DAC_CS_ASSERT
andrewm@0 420 DAC_TX reg
andrewm@0 421 DAC_WAIT_FOR_FINISH
andrewm@0 422 DAC_CS_UNASSERT
andrewm@0 423 DAC_DISCARD_RX
andrewm@0 424 .endm
andrewm@0 425
andrewm@0 426 // Bring CS line low to write to ADC
andrewm@0 427 .macro ADC_CS_ASSERT
andrewm@0 428 MOV r27, ADC_CS_PIN
andrewm@0 429 MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT
andrewm@0 430 SBBO r27, r28, 0, 4
andrewm@0 431 .endm
andrewm@0 432
andrewm@0 433 // Bring CS line high at end of ADC transaction
andrewm@0 434 .macro ADC_CS_UNASSERT
andrewm@0 435 MOV r27, ADC_CS_PIN
andrewm@0 436 MOV r28, ADC_GPIO + GPIO_SETDATAOUT
andrewm@0 437 SBBO r27, r28, 0, 4
andrewm@0 438 .endm
andrewm@0 439
andrewm@0 440 // Write to ADC TX register
andrewm@0 441 .macro ADC_TX
andrewm@0 442 .mparam data
andrewm@0 443 SBBO data, reg_spi_addr, SPI_CH1TX, 4
andrewm@0 444 .endm
andrewm@0 445
andrewm@0 446 // Wait for SPI to finish (uses RXS indicator)
andrewm@0 447 .macro ADC_WAIT_FOR_FINISH
andrewm@0 448 LOOP:
andrewm@0 449 LBBO r27, reg_spi_addr, SPI_CH1STAT, 4
andrewm@0 450 QBBC LOOP, r27, 0
andrewm@0 451 .endm
andrewm@0 452
andrewm@0 453 // Read the RX word to clear; store output
andrewm@0 454 .macro ADC_RX
andrewm@0 455 .mparam data
andrewm@0 456 LBBO data, reg_spi_addr, SPI_CH1RX, 4
andrewm@0 457 .endm
andrewm@0 458
andrewm@0 459 // Complete ADC write+read with chip select
andrewm@0 460 .macro ADC_WRITE
andrewm@0 461 .mparam in, out
andrewm@0 462 ADC_CS_ASSERT
andrewm@0 463 ADC_TX in
andrewm@0 464 ADC_WAIT_FOR_FINISH
andrewm@0 465 ADC_RX out
andrewm@0 466 ADC_CS_UNASSERT
andrewm@0 467 .endm
andrewm@0 468
andrewm@0 469 // Write a McASP register
andrewm@0 470 .macro MCASP_REG_WRITE
andrewm@0 471 .mparam reg, value
andrewm@0 472 MOV r27, value
andrewm@0 473 SBBO r27, reg_mcasp_addr, reg, 4
andrewm@0 474 .endm
andrewm@0 475
andrewm@0 476 // Write a McASP register beyond the 0xFF boundary
andrewm@0 477 .macro MCASP_REG_WRITE_EXT
andrewm@0 478 .mparam reg, value
andrewm@0 479 MOV r27, value
andrewm@0 480 MOV r28, reg
andrewm@0 481 ADD r28, reg_mcasp_addr, r28
andrewm@0 482 SBBO r27, r28, 0, 4
andrewm@0 483 .endm
andrewm@0 484
andrewm@0 485 // Read a McASP register
andrewm@0 486 .macro MCASP_REG_READ
andrewm@0 487 .mparam reg, value
andrewm@0 488 LBBO value, reg_mcasp_addr, reg, 4
andrewm@0 489 .endm
andrewm@0 490
andrewm@0 491 // Read a McASP register beyond the 0xFF boundary
andrewm@0 492 .macro MCASP_REG_READ_EXT
andrewm@0 493 .mparam reg, value
andrewm@0 494 MOV r28, reg
andrewm@0 495 ADD r28, reg_mcasp_addr, r28
andrewm@0 496 LBBO value, r28, 0, 4
andrewm@0 497 .endm
andrewm@0 498
andrewm@0 499 // Set a bit and wait for it to come up
andrewm@0 500 .macro MCASP_REG_SET_BIT_AND_POLL
andrewm@0 501 .mparam reg, mask
andrewm@0 502 MOV r27, mask
andrewm@0 503 LBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 504 OR r28, r28, r27
andrewm@0 505 SBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 506 POLL:
andrewm@0 507 LBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 508 AND r28, r28, r27
andrewm@0 509 QBEQ POLL, r28, 0
andrewm@0 510 .endm
andrewm@0 511
andrewm@0 512 START:
andrewm@0 513 // Set up c24 and c25 offsets with CTBIR register
andrewm@0 514 // Thus C24 points to start of PRU0 RAM
andrewm@0 515 MOV r3, 0x22020 // CTBIR0
andrewm@0 516 MOV r2, 0
andrewm@0 517 SBBO r2, r3, 0, 4
andrewm@0 518
andrewm@0 519 // Set up c28 pointer offset for shared PRU RAM
andrewm@0 520 MOV r3, 0x22028 // CTPPR0
andrewm@0 521 MOV r2, 0x00000120 // To get address 0x00012000
andrewm@0 522 SBBO r2, r3, 0, 4
andrewm@0 523
andrewm@0 524 // Load useful registers for addressing SPI
andrewm@0 525 MOV reg_comm_addr, SHARED_COMM_MEM_BASE
andrewm@0 526 MOV reg_spi_addr, SPI_BASE
andrewm@0 527 MOV reg_mcasp_addr, MCASP_BASE
andrewm@0 528
andrewm@0 529 // Set ARM such that PRU can write to registers
andrewm@0 530 LBCO r0, C4, 4, 4
andrewm@0 531 CLR r0, r0, 4
andrewm@0 532 SBCO r0, C4, 4, 4
andrewm@0 533
andrewm@0 534 // Clear flags
andrewm@0 535 MOV reg_flags, 0
andrewm@0 536
andrewm@12 537 // Default number of channels in case SPI disabled
andrewm@12 538 LDI reg_num_channels, 8
andrewm@12 539
andrewm@0 540 // Find out whether we should use SPI ADC and DAC
andrewm@0 541 LBBO r2, reg_comm_addr, COMM_USE_SPI, 4
andrewm@0 542 QBEQ SPI_FLAG_CHECK_DONE, r2, 0
andrewm@0 543 SET reg_flags, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 544
andrewm@0 545 SPI_FLAG_CHECK_DONE:
andrewm@0 546 // If we don't use SPI, then skip all this init
andrewm@0 547 QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@12 548
andrewm@12 549 // Load the number of channels: valid values are 8, 4 or 2
andrewm@12 550 LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4
andrewm@12 551 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ?
andrewm@12 552 LDI reg_num_channels, 8 // If N >= 8, N = 8
andrewm@12 553 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 554 SPI_NUM_CHANNELS_LT8:
andrewm@12 555 QBGT SPI_NUM_CHANNELS_LT4, reg_num_channels, 4 // 4 > num_channels ?
andrewm@12 556 LDI reg_num_channels, 4 // If N >= 4, N = 4
andrewm@12 557 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 558 SPI_NUM_CHANNELS_LT4:
andrewm@12 559 LDI reg_num_channels, 2 // else N = 2
andrewm@12 560 SPI_NUM_CHANNELS_DONE:
andrewm@0 561
andrewm@0 562 // Init SPI clock
andrewm@0 563 MOV r2, 0x02
andrewm@0 564 MOV r3, CLOCK_BASE + CLOCK_SPI0
andrewm@0 565 SBBO r2, r3, 0, 4
andrewm@0 566
andrewm@0 567 // Reset SPI and wait for finish
andrewm@0 568 MOV r2, 0x02
andrewm@0 569 SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4
andrewm@0 570
andrewm@0 571 SPI_WAIT_RESET:
andrewm@0 572 LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4
andrewm@0 573 QBBC SPI_WAIT_RESET, r2, 0
andrewm@0 574
andrewm@0 575 // Turn off SPI channels
andrewm@0 576 MOV r2, 0
andrewm@0 577 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
andrewm@0 578 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 579
andrewm@0 580 // Set to master; chip select lines enabled (CS0 used for DAC)
andrewm@0 581 MOV r2, 0x00
andrewm@0 582 SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4
andrewm@0 583
andrewm@0 584 // Configure CH0 for DAC
andrewm@0 585 MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6)
andrewm@0 586 SBBO r2, reg_spi_addr, SPI_CH0CONF, 4
andrewm@0 587
andrewm@0 588 // Configure CH1 for ADC
andrewm@0 589 MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE
andrewm@0 590 SBBO r2, reg_spi_addr, SPI_CH1CONF, 4
andrewm@0 591
andrewm@0 592 // Turn on SPI channels
andrewm@0 593 MOV r2, 0x01
andrewm@0 594 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
andrewm@0 595 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 596
andrewm@0 597 // DAC power-on reset sequence
andrewm@0 598 MOV r2, (0x07 << AD5668_COMMAND_OFFSET)
andrewm@0 599 DAC_WRITE r2
andrewm@0 600
andrewm@0 601 // Initialise ADC
andrewm@0 602 MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET)
andrewm@0 603 ADC_WRITE r2, r2
andrewm@0 604
andrewm@0 605 // Enable DAC internal reference
andrewm@0 606 MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET)
andrewm@0 607 DAC_WRITE r2
andrewm@0 608
andrewm@0 609 // Read ADC ch0 and ch1: result is always 2 samples behind so start here
andrewm@0 610 MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET)
andrewm@0 611 ADC_WRITE r2, r2
andrewm@0 612
andrewm@0 613 MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET)
andrewm@0 614 ADC_WRITE r2, r2
andrewm@0 615 SPI_INIT_DONE:
andrewm@0 616
andrewm@21 617 // Prepare McASP0 for audio
andrewm@21 618 MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP
andrewm@21 619 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off
andrewm@21 620 MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0
andrewm@21 621 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0
andrewm@21 622 MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0
andrewm@21 623 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0
andrewm@21 624 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0
andrewm@0 625
andrewm@21 626 MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on
andrewm@21 627 MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP
andrewm@21 628 MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction
andrewm@21 629 MCASP_REG_WRITE MCASP_DLBCTL, 0x00
andrewm@21 630 MCASP_REG_WRITE MCASP_DITCTL, 0x00
andrewm@21 631 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive
andrewm@21 632 MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format
andrewm@21 633 MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode
andrewm@21 634 MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge
andrewm@21 635 MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant?
andrewm@21 636 MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1
andrewm@21 637 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts
andrewm@21 638 MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit
andrewm@21 639 MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format
andrewm@21 640 MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode
andrewm@21 641 MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv
andrewm@21 642 MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX
andrewm@21 643 MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1
andrewm@21 644 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts
andrewm@0 645
andrewm@21 646 MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser
andrewm@21 647 MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser
andrewm@21 648 MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs
andrewm@21 649 MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00
andrewm@0 650
andrewm@21 651 MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors
andrewm@21 652 MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors
andrewm@0 653
andrewm@21 654 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST
andrewm@21 655 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST
andrewm@0 656
andrewm@0 657 // The above write sequence will have temporarily changed the AHCLKX frequency
andrewm@0 658 // The PLL needs time to settle or the sample rate will be unstable and possibly
andrewm@0 659 // cause an underrun. Give it ~1ms before going on.
andrewm@0 660 // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed
andrewm@0 661
andrewm@0 662 MOV r2, 1 << 28
andrewm@0 663 MOV r3, GPIO1 + GPIO_SETDATAOUT
andrewm@0 664 SBBO r2, r3, 0, 4
andrewm@0 665
andrewm@21 666 MOV r2, 100000
andrewm@0 667 MCASP_INIT_WAIT:
andrewm@0 668 SUB r2, r2, 1
andrewm@0 669 QBNE MCASP_INIT_WAIT, r2, 0
andrewm@0 670
andrewm@0 671 MOV r2, 1 << 28
andrewm@0 672 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
andrewm@0 673 SBBO r2, r3, 0, 4
andrewm@0 674
andrewm@21 675 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST
andrewm@21 676 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST
andrewm@21 677 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR
andrewm@21 678 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR
andrewm@21 679 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST
andrewm@21 680 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST
andrewm@0 681
andrewm@21 682 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow
andrewm@0 683
andrewm@21 684 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST
andrewm@21 685 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST
andrewm@0 686
andrewm@0 687 // Initialisation
andrewm@21 688 LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP)
andrewm@21 689 MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer
andrewm@21 690 LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize
andrewm@21 691 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels
andrewm@21 692 LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above
andrewm@21 693 MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer
andrewm@21 694 LSL reg_mcasp_buf1, reg_frame_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize
andrewm@21 695 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on
andrewm@21 696 MOV r2, 0
andrewm@21 697 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0
andrewm@0 698
andrewm@0 699 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied
andrewm@0 700 // the first output slot. Send one more word before jumping into the loop.
andrewm@0 701 MCASP_DAC_WAIT_BEFORE_LOOP:
andrewm@0 702 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
andrewm@0 703 QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 704
andrewm@0 705 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00
andrewm@0 706
andrewm@0 707 // Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC
andrewm@0 708 // in sync in terms of which TDM slot we are reading (empirically found that we should throw this away
andrewm@0 709 // rather than keep it and invert the phase)
andrewm@0 710 MCASP_ADC_WAIT_BEFORE_LOOP:
andrewm@0 711 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
andrewm@0 712 QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 713
andrewm@0 714 MCASP_REG_READ_EXT MCASP_RBUF, r2
andrewm@0 715
andrewm@0 716 WRITE_ONE_BUFFER:
andrewm@0 717 // Write a single buffer of DAC samples and read a buffer of ADC samples
andrewm@0 718 // Load starting positions
andrewm@0 719 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer
andrewm@12 720 LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels
andrewm@12 721 LSL reg_adc_current, reg_frame_total, r2
andrewm@12 722 LSL reg_adc_current, reg_adc_current, 2 // N * 2 * 2 * bufsize
andrewm@12 723 ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC
andrewm@0 724 MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
andrewm@12 725 LSL reg_mcasp_adc_current, reg_frame_total, r2 // McASP ADC: starts (N/2)*2*2*bufsize beyond DAC
andrewm@12 726 LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1
andrewm@0 727 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current
andrewm@0 728 MOV reg_frame_current, 0
andrewm@0 729
andrewm@0 730 WRITE_LOOP:
andrewm@12 731 // Write N channels to DAC from successive values in memory
andrewm@12 732 // At the same time, read N channels from ADC
andrewm@0 733 // Unrolled by a factor of 2 to get high and low words
andrewm@0 734 MOV r1, 0
andrewm@0 735 ADC_DAC_LOOP:
andrewm@0 736 QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 737 // Load next 2 SPI DAC samples and store zero in their place
andrewm@0 738 LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4
andrewm@0 739 MOV r2, 0
andrewm@0 740 SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4
andrewm@0 741 ADD reg_dac_current, reg_dac_current, 4
andrewm@0 742 SPI_DAC_LOAD_DONE:
andrewm@0 743
andrewm@0 744 // On even iterations, load two more samples and choose the first one
andrewm@0 745 // On odd iterations, transmit the second of the samples already loaded
andrewm@12 746 // QBBS MCASP_DAC_HIGH_WORD, r1, 1
andrewm@12 747 QBBS MCASP_DAC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 748 MCASP_DAC_LOW_WORD:
andrewm@0 749 // Load next 2 Audio DAC samples and store zero in their place
andrewm@0 750 LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
andrewm@0 751 MOV r2, 0
andrewm@0 752 SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4
andrewm@0 753 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4
andrewm@0 754
andrewm@0 755 // Mask out the low word (first in little endian)
andrewm@0 756 MOV r2, 0xFFFF
andrewm@0 757 AND r7, reg_mcasp_dac_data, r2
andrewm@0 758
andrewm@0 759 QBA MCASP_WAIT_XSTAT
andrewm@0 760 MCASP_DAC_HIGH_WORD:
andrewm@0 761 // Take the high word of the previously loaded data
andrewm@0 762 LSR r7, reg_mcasp_dac_data, 16
andrewm@0 763
andrewm@12 764 // Every 2 channels we send one audio sample; this loop already
andrewm@0 765 // sends exactly two SPI channels.
andrewm@0 766 // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
andrewm@0 767 MCASP_WAIT_XSTAT:
andrewm@0 768 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
andrewm@0 769 QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 770
andrewm@0 771 MCASP_REG_WRITE_EXT MCASP_XBUF, r7
andrewm@0 772
andrewm@0 773 // Same idea with ADC: even iterations, load the sample into the low word, odd
andrewm@0 774 // iterations, load the sample into the high word and store
andrewm@12 775 // QBBS MCASP_ADC_HIGH_WORD, r1, 1
andrewm@12 776 QBBS MCASP_ADC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 777 MCASP_ADC_LOW_WORD:
andrewm@0 778 // Start ADC data at 0
andrewm@0 779 LDI reg_mcasp_adc_data, 0
andrewm@0 780
andrewm@0 781 // Now wait for a received word to become available from the audio ADC
andrewm@0 782 MCASP_WAIT_RSTAT_LOW:
andrewm@0 783 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
andrewm@0 784 QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 785
andrewm@0 786 // Mask low word and store in ADC data register
andrewm@0 787 MCASP_REG_READ_EXT MCASP_RBUF, r3
andrewm@0 788 MOV r2, 0xFFFF
andrewm@0 789 AND reg_mcasp_adc_data, r3, r2
andrewm@0 790 QBA MCASP_ADC_DONE
andrewm@0 791
andrewm@0 792 MCASP_ADC_HIGH_WORD:
andrewm@0 793 // Wait for a received word to become available from the audio ADC
andrewm@0 794 MCASP_WAIT_RSTAT_HIGH:
andrewm@0 795 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
andrewm@0 796 QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 797
andrewm@0 798 // Read data and shift 16 bits to the left (into the high word)
andrewm@0 799 MCASP_REG_READ_EXT MCASP_RBUF, r3
andrewm@0 800 LSL r3, r3, 16
andrewm@0 801 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3
andrewm@0 802
andrewm@0 803 // Now store the result and increment the pointer
andrewm@0 804 SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4
andrewm@0 805 ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4
andrewm@0 806 MCASP_ADC_DONE:
andrewm@0 807 QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 808
andrewm@0 809 // DAC: transmit low word (first in little endian)
andrewm@0 810 MOV r2, 0xFFFF
andrewm@0 811 AND r7, reg_dac_data, r2
andrewm@0 812 LSL r7, r7, AD5668_DATA_OFFSET
andrewm@0 813 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
andrewm@0 814 OR r7, r7, r8
andrewm@0 815 LSL r8, r1, AD5668_ADDRESS_OFFSET
andrewm@0 816 OR r7, r7, r8
andrewm@0 817 DAC_WRITE r7
andrewm@0 818
andrewm@0 819 // Read ADC channels: result is always 2 commands behind
andrewm@0 820 // Start by reading channel 2 (result is channel 0) and go
andrewm@12 821 // to N+2, but masking the channel number to be between 0 and N-1
andrewm@0 822 LDI reg_adc_data, 0
andrewm@12 823 ADD r8, r1, 2
andrewm@12 824 SUB r7, reg_num_channels, 1
andrewm@12 825 AND r8, r8, r7
andrewm@12 826 LSL r8, r8, AD7699_CHANNEL_OFFSET
andrewm@0 827 MOV r7, AD7699_CFG_MASK
andrewm@0 828 OR r7, r7, r8
andrewm@0 829 ADC_WRITE r7, r7
andrewm@0 830
andrewm@0 831 // Mask out only the relevant 16 bits and store in reg_adc_data
andrewm@0 832 MOV r2, 0xFFFF
andrewm@0 833 AND reg_adc_data, r7, r2
andrewm@0 834
andrewm@0 835 // Increment channel index
andrewm@0 836 ADD r1, r1, 1
andrewm@0 837
andrewm@0 838 // DAC: transmit high word (second in little endian)
andrewm@0 839 LSR r7, reg_dac_data, 16
andrewm@0 840 LSL r7, r7, AD5668_DATA_OFFSET
andrewm@0 841 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
andrewm@0 842 OR r7, r7, r8
andrewm@0 843 LSL r8, r1, AD5668_ADDRESS_OFFSET
andrewm@0 844 OR r7, r7, r8
andrewm@0 845 DAC_WRITE r7
andrewm@0 846
andrewm@0 847 // Read ADC channels: result is always 2 commands behind
andrewm@0 848 // Start by reading channel 2 (result is channel 0) and go
andrewm@12 849 // to N+2, but masking the channel number to be between 0 and N-1
andrewm@12 850 ADD r8, r1, 2
andrewm@12 851 SUB r7, reg_num_channels, 1
andrewm@12 852 AND r8, r8, r7
andrewm@12 853 LSL r8, r8, AD7699_CHANNEL_OFFSET
andrewm@0 854 MOV r7, AD7699_CFG_MASK
andrewm@0 855 OR r7, r7, r8
andrewm@0 856 ADC_WRITE r7, r7
andrewm@0 857
andrewm@0 858 // Move this result up to the 16 high bits
andrewm@0 859 LSL r7, r7, 16
andrewm@0 860 OR reg_adc_data, reg_adc_data, r7
andrewm@0 861
andrewm@0 862 // Store 2 ADC words in memory
andrewm@0 863 SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
andrewm@0 864 ADD reg_adc_current, reg_adc_current, 4
andrewm@0 865
andrewm@12 866 // Toggle the high/low word for McASP control (since we send one word out of
andrewm@12 867 // 32 bits for each pair of SPI channels)
andrewm@12 868 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
andrewm@12 869
andrewm@12 870 // Repeat 4 times for 8 channels (2 samples per loop, r1 += 1 already happened)
andrewm@12 871 // For 4 or 2 channels, repeat 2 or 1 times, according to flags
andrewm@0 872 ADD r1, r1, 1
andrewm@12 873 QBNE ADC_DAC_LOOP, r1, reg_num_channels
andrewm@0 874 QBA ADC_DAC_LOOP_DONE
andrewm@12 875
andrewm@0 876 SPI_SKIP_WRITE:
andrewm@0 877 // We get here only if the SPI ADC and DAC are disabled
andrewm@0 878 // Just keep the loop going for McASP
andrewm@12 879
andrewm@12 880 // Toggle the high/low word for McASP control (since we send one word out of
andrewm@12 881 // 32 bits for each pair of SPI channels)
andrewm@12 882 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
andrewm@12 883
andrewm@0 884 ADD r1, r1, 2
andrewm@12 885 QBNE ADC_DAC_LOOP, r1, reg_num_channels
andrewm@0 886
andrewm@0 887 ADC_DAC_LOOP_DONE:
andrewm@0 888 // Increment number of frames, see if we have more to write
andrewm@0 889 ADD reg_frame_current, reg_frame_current, 1
andrewm@0 890 QBNE WRITE_LOOP, reg_frame_current, reg_frame_total
andrewm@0 891
andrewm@0 892 WRITE_LOOP_DONE:
andrewm@0 893 // Now done, swap the buffers and do the next one
andrewm@0 894 // Use r2 as a temp register
andrewm@0 895 MOV r2, reg_dac_buf0
andrewm@0 896 MOV reg_dac_buf0, reg_dac_buf1
andrewm@0 897 MOV reg_dac_buf1, r2
andrewm@0 898 MOV r2, reg_mcasp_buf0
andrewm@0 899 MOV reg_mcasp_buf0, reg_mcasp_buf1
andrewm@0 900 MOV reg_mcasp_buf1, r2
andrewm@0 901
andrewm@0 902 // Notify ARM of buffer swap
andrewm@0 903 XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1)
andrewm@0 904 AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit
andrewm@0 905 SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4
andrewm@0 906
andrewm@0 907 // Increment the frame count in the comm buffer (for status monitoring)
andrewm@0 908 LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
andrewm@0 909 ADD r2, r2, reg_frame_total
andrewm@0 910 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
andrewm@0 911
andrewm@0 912 // If LED blink enabled, toggle every 4096 frames
andrewm@0 913 LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4
andrewm@0 914 QBEQ LED_BLINK_DONE, r3, 0
andrewm@0 915 MOV r1, 0x1000
andrewm@0 916 AND r2, r2, r1 // Test (frame count & 4096)
andrewm@0 917 QBEQ LED_BLINK_OFF, r2, 0
andrewm@0 918 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
andrewm@0 919 MOV r1, GPIO_SETDATAOUT
andrewm@0 920 ADD r3, r3, r1 // Address for GPIO set register
andrewm@0 921 SBBO r2, r3, 0, 4 // Set GPIO pin
andrewm@0 922 QBA LED_BLINK_DONE
andrewm@0 923 LED_BLINK_OFF:
andrewm@0 924 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
andrewm@0 925 MOV r1, GPIO_CLEARDATAOUT
andrewm@0 926 ADD r3, r3, r1 // Address for GPIO clear register
andrewm@0 927 SBBO r2, r3, 0, 4 // Clear GPIO pin
andrewm@0 928 LED_BLINK_DONE:
andrewm@0 929
andrewm@0 930 QBBC TESTLOW, reg_flags, FLAG_BIT_BUFFER1
andrewm@0 931 MOV r2, 1 << 28
andrewm@0 932 MOV r3, GPIO1 + GPIO_SETDATAOUT
andrewm@0 933 SBBO r2, r3, 0, 4
andrewm@0 934 QBA TESTDONE
andrewm@0 935 TESTLOW:
andrewm@0 936 MOV r2, 1 << 28
andrewm@0 937 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
andrewm@0 938 SBBO r2, r3, 0, 4
andrewm@0 939 TESTDONE:
andrewm@0 940
andrewm@0 941 // Check if we should finish: flag is zero as long as it should run
andrewm@0 942 LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4
andrewm@0 943 QBEQ WRITE_ONE_BUFFER, r2, 0
andrewm@0 944
andrewm@0 945 CLEANUP:
andrewm@0 946 MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP
andrewm@0 947
andrewm@0 948 // Turn off SPI if enabled
andrewm@0 949 QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 950
andrewm@0 951 MOV r3, SPI_BASE + SPI_CH0CONF
andrewm@0 952 LBBO r2, r3, 0, 4
andrewm@0 953 CLR r2, r2, 13
andrewm@0 954 CLR r2, r2, 27
andrewm@0 955 SBBO r2, r3, 0, 4
andrewm@0 956
andrewm@0 957 MOV r3, SPI_BASE + SPI_CH0CTRL
andrewm@0 958 LBBO r2, r3, 0, 4
andrewm@0 959 CLR r2, r2, 1
andrewm@0 960 SBBO r2, r3, 0, 4
andrewm@0 961 SPI_CLEANUP_DONE:
andrewm@0 962
andrewm@0 963 // Signal the ARM that we have finished
andrewm@0 964 MOV R31.b0, PRU0_ARM_INTERRUPT + 16
andrewm@0 965 HALT