annotate pru_rtaudio.p @ 12:a6beeba3a648

Initial support for higher matrix sample rates by reducing the number of channels. Input not tested yet, and not all examples updated to new format.
author andrewm
date Thu, 22 Jan 2015 19:00:22 +0000
parents 8a575ba3ab52
children 6adb088196a7
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@0 208
andrewm@0 209 // Bring CS line low to write to DAC
andrewm@0 210 .macro DAC_CS_ASSERT
andrewm@0 211 MOV r27, DAC_CS_PIN
andrewm@0 212 MOV r28, DAC_GPIO + GPIO_CLEARDATAOUT
andrewm@0 213 SBBO r27, r28, 0, 4
andrewm@0 214 .endm
andrewm@0 215
andrewm@0 216 // Bring CS line high at end of DAC transaction
andrewm@0 217 .macro DAC_CS_UNASSERT
andrewm@0 218 MOV r27, DAC_CS_PIN
andrewm@0 219 MOV r28, DAC_GPIO + GPIO_SETDATAOUT
andrewm@0 220 SBBO r27, r28, 0, 4
andrewm@0 221 .endm
andrewm@0 222
andrewm@0 223 // Write to DAC TX register
andrewm@0 224 .macro DAC_TX
andrewm@0 225 .mparam data
andrewm@0 226 SBBO data, reg_spi_addr, SPI_CH0TX, 4
andrewm@0 227 .endm
andrewm@0 228
andrewm@0 229 // Wait for SPI to finish (uses RXS indicator)
andrewm@0 230 .macro DAC_WAIT_FOR_FINISH
andrewm@0 231 LOOP:
andrewm@0 232 LBBO r27, reg_spi_addr, SPI_CH0STAT, 4
andrewm@0 233 QBBC LOOP, r27, 0
andrewm@0 234 .endm
andrewm@0 235
andrewm@0 236 // Read the RX word to clear
andrewm@0 237 .macro DAC_DISCARD_RX
andrewm@0 238 LBBO r27, reg_spi_addr, SPI_CH0RX, 4
andrewm@0 239 .endm
andrewm@0 240
andrewm@0 241 // Complete DAC write with chip select
andrewm@0 242 .macro DAC_WRITE
andrewm@0 243 .mparam reg
andrewm@0 244 DAC_CS_ASSERT
andrewm@0 245 DAC_TX reg
andrewm@0 246 DAC_WAIT_FOR_FINISH
andrewm@0 247 DAC_CS_UNASSERT
andrewm@0 248 DAC_DISCARD_RX
andrewm@0 249 .endm
andrewm@0 250
andrewm@0 251 // Bring CS line low to write to ADC
andrewm@0 252 .macro ADC_CS_ASSERT
andrewm@0 253 MOV r27, ADC_CS_PIN
andrewm@0 254 MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT
andrewm@0 255 SBBO r27, r28, 0, 4
andrewm@0 256 .endm
andrewm@0 257
andrewm@0 258 // Bring CS line high at end of ADC transaction
andrewm@0 259 .macro ADC_CS_UNASSERT
andrewm@0 260 MOV r27, ADC_CS_PIN
andrewm@0 261 MOV r28, ADC_GPIO + GPIO_SETDATAOUT
andrewm@0 262 SBBO r27, r28, 0, 4
andrewm@0 263 .endm
andrewm@0 264
andrewm@0 265 // Write to ADC TX register
andrewm@0 266 .macro ADC_TX
andrewm@0 267 .mparam data
andrewm@0 268 SBBO data, reg_spi_addr, SPI_CH1TX, 4
andrewm@0 269 .endm
andrewm@0 270
andrewm@0 271 // Wait for SPI to finish (uses RXS indicator)
andrewm@0 272 .macro ADC_WAIT_FOR_FINISH
andrewm@0 273 LOOP:
andrewm@0 274 LBBO r27, reg_spi_addr, SPI_CH1STAT, 4
andrewm@0 275 QBBC LOOP, r27, 0
andrewm@0 276 .endm
andrewm@0 277
andrewm@0 278 // Read the RX word to clear; store output
andrewm@0 279 .macro ADC_RX
andrewm@0 280 .mparam data
andrewm@0 281 LBBO data, reg_spi_addr, SPI_CH1RX, 4
andrewm@0 282 .endm
andrewm@0 283
andrewm@0 284 // Complete ADC write+read with chip select
andrewm@0 285 .macro ADC_WRITE
andrewm@0 286 .mparam in, out
andrewm@0 287 ADC_CS_ASSERT
andrewm@0 288 ADC_TX in
andrewm@0 289 ADC_WAIT_FOR_FINISH
andrewm@0 290 ADC_RX out
andrewm@0 291 ADC_CS_UNASSERT
andrewm@0 292 .endm
andrewm@0 293
andrewm@0 294 // Write a McASP register
andrewm@0 295 .macro MCASP_REG_WRITE
andrewm@0 296 .mparam reg, value
andrewm@0 297 MOV r27, value
andrewm@0 298 SBBO r27, reg_mcasp_addr, reg, 4
andrewm@0 299 .endm
andrewm@0 300
andrewm@0 301 // Write a McASP register beyond the 0xFF boundary
andrewm@0 302 .macro MCASP_REG_WRITE_EXT
andrewm@0 303 .mparam reg, value
andrewm@0 304 MOV r27, value
andrewm@0 305 MOV r28, reg
andrewm@0 306 ADD r28, reg_mcasp_addr, r28
andrewm@0 307 SBBO r27, r28, 0, 4
andrewm@0 308 .endm
andrewm@0 309
andrewm@0 310 // Read a McASP register
andrewm@0 311 .macro MCASP_REG_READ
andrewm@0 312 .mparam reg, value
andrewm@0 313 LBBO value, reg_mcasp_addr, reg, 4
andrewm@0 314 .endm
andrewm@0 315
andrewm@0 316 // Read a McASP register beyond the 0xFF boundary
andrewm@0 317 .macro MCASP_REG_READ_EXT
andrewm@0 318 .mparam reg, value
andrewm@0 319 MOV r28, reg
andrewm@0 320 ADD r28, reg_mcasp_addr, r28
andrewm@0 321 LBBO value, r28, 0, 4
andrewm@0 322 .endm
andrewm@0 323
andrewm@0 324 // Set a bit and wait for it to come up
andrewm@0 325 .macro MCASP_REG_SET_BIT_AND_POLL
andrewm@0 326 .mparam reg, mask
andrewm@0 327 MOV r27, mask
andrewm@0 328 LBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 329 OR r28, r28, r27
andrewm@0 330 SBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 331 POLL:
andrewm@0 332 LBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 333 AND r28, r28, r27
andrewm@0 334 QBEQ POLL, r28, 0
andrewm@0 335 .endm
andrewm@0 336
andrewm@0 337 START:
andrewm@0 338 // Set up c24 and c25 offsets with CTBIR register
andrewm@0 339 // Thus C24 points to start of PRU0 RAM
andrewm@0 340 MOV r3, 0x22020 // CTBIR0
andrewm@0 341 MOV r2, 0
andrewm@0 342 SBBO r2, r3, 0, 4
andrewm@0 343
andrewm@0 344 // Set up c28 pointer offset for shared PRU RAM
andrewm@0 345 MOV r3, 0x22028 // CTPPR0
andrewm@0 346 MOV r2, 0x00000120 // To get address 0x00012000
andrewm@0 347 SBBO r2, r3, 0, 4
andrewm@0 348
andrewm@0 349 // Load useful registers for addressing SPI
andrewm@0 350 MOV reg_comm_addr, SHARED_COMM_MEM_BASE
andrewm@0 351 MOV reg_spi_addr, SPI_BASE
andrewm@0 352 MOV reg_mcasp_addr, MCASP_BASE
andrewm@0 353
andrewm@0 354 // Set ARM such that PRU can write to registers
andrewm@0 355 LBCO r0, C4, 4, 4
andrewm@0 356 CLR r0, r0, 4
andrewm@0 357 SBCO r0, C4, 4, 4
andrewm@0 358
andrewm@0 359 // Clear flags
andrewm@0 360 MOV reg_flags, 0
andrewm@0 361
andrewm@12 362 // Default number of channels in case SPI disabled
andrewm@12 363 LDI reg_num_channels, 8
andrewm@12 364
andrewm@0 365 // Find out whether we should use SPI ADC and DAC
andrewm@0 366 LBBO r2, reg_comm_addr, COMM_USE_SPI, 4
andrewm@0 367 QBEQ SPI_FLAG_CHECK_DONE, r2, 0
andrewm@0 368 SET reg_flags, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 369
andrewm@0 370 SPI_FLAG_CHECK_DONE:
andrewm@0 371 // If we don't use SPI, then skip all this init
andrewm@0 372 QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@12 373
andrewm@12 374 // Load the number of channels: valid values are 8, 4 or 2
andrewm@12 375 LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4
andrewm@12 376 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ?
andrewm@12 377 LDI reg_num_channels, 8 // If N >= 8, N = 8
andrewm@12 378 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 379 SPI_NUM_CHANNELS_LT8:
andrewm@12 380 QBGT SPI_NUM_CHANNELS_LT4, reg_num_channels, 4 // 4 > num_channels ?
andrewm@12 381 LDI reg_num_channels, 4 // If N >= 4, N = 4
andrewm@12 382 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 383 SPI_NUM_CHANNELS_LT4:
andrewm@12 384 LDI reg_num_channels, 2 // else N = 2
andrewm@12 385 SPI_NUM_CHANNELS_DONE:
andrewm@0 386
andrewm@0 387 // Init SPI clock
andrewm@0 388 MOV r2, 0x02
andrewm@0 389 MOV r3, CLOCK_BASE + CLOCK_SPI0
andrewm@0 390 SBBO r2, r3, 0, 4
andrewm@0 391
andrewm@0 392 // Reset SPI and wait for finish
andrewm@0 393 MOV r2, 0x02
andrewm@0 394 SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4
andrewm@0 395
andrewm@0 396 SPI_WAIT_RESET:
andrewm@0 397 LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4
andrewm@0 398 QBBC SPI_WAIT_RESET, r2, 0
andrewm@0 399
andrewm@0 400 // Turn off SPI channels
andrewm@0 401 MOV r2, 0
andrewm@0 402 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
andrewm@0 403 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 404
andrewm@0 405 // Set to master; chip select lines enabled (CS0 used for DAC)
andrewm@0 406 MOV r2, 0x00
andrewm@0 407 SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4
andrewm@0 408
andrewm@0 409 // Configure CH0 for DAC
andrewm@0 410 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 411 SBBO r2, reg_spi_addr, SPI_CH0CONF, 4
andrewm@0 412
andrewm@0 413 // Configure CH1 for ADC
andrewm@0 414 MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE
andrewm@0 415 SBBO r2, reg_spi_addr, SPI_CH1CONF, 4
andrewm@0 416
andrewm@0 417 // Turn on SPI channels
andrewm@0 418 MOV r2, 0x01
andrewm@0 419 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
andrewm@0 420 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 421
andrewm@0 422 // DAC power-on reset sequence
andrewm@0 423 MOV r2, (0x07 << AD5668_COMMAND_OFFSET)
andrewm@0 424 DAC_WRITE r2
andrewm@0 425
andrewm@0 426 // Initialise ADC
andrewm@0 427 MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET)
andrewm@0 428 ADC_WRITE r2, r2
andrewm@0 429
andrewm@0 430 // Enable DAC internal reference
andrewm@0 431 MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET)
andrewm@0 432 DAC_WRITE r2
andrewm@0 433
andrewm@0 434 // Read ADC ch0 and ch1: result is always 2 samples behind so start here
andrewm@0 435 MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET)
andrewm@0 436 ADC_WRITE r2, r2
andrewm@0 437
andrewm@0 438 MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET)
andrewm@0 439 ADC_WRITE r2, r2
andrewm@0 440 SPI_INIT_DONE:
andrewm@0 441
andrewm@0 442 // Prepare McASP0 for audio
andrewm@0 443 MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP
andrewm@0 444 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off
andrewm@0 445 MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0
andrewm@0 446 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0
andrewm@0 447 MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0
andrewm@0 448 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0
andrewm@0 449 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0
andrewm@0 450
andrewm@0 451 MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on
andrewm@0 452 MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP
andrewm@0 453 MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction
andrewm@0 454 MCASP_REG_WRITE MCASP_DLBCTL, 0x00
andrewm@0 455 MCASP_REG_WRITE MCASP_DITCTL, 0x00
andrewm@0 456 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive
andrewm@0 457 MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format
andrewm@0 458 MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode
andrewm@0 459 MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge
andrewm@0 460 MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant?
andrewm@0 461 MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1
andrewm@0 462 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts
andrewm@0 463 MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit
andrewm@0 464 MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format
andrewm@0 465 MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode
andrewm@0 466 MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv
andrewm@0 467 MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX
andrewm@0 468 MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1
andrewm@0 469 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts
andrewm@0 470
andrewm@0 471 MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser
andrewm@0 472 MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser
andrewm@0 473 MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs
andrewm@0 474 MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00
andrewm@0 475
andrewm@0 476 MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors
andrewm@0 477 MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors
andrewm@0 478
andrewm@0 479 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST
andrewm@0 480 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST
andrewm@0 481
andrewm@0 482 // The above write sequence will have temporarily changed the AHCLKX frequency
andrewm@0 483 // The PLL needs time to settle or the sample rate will be unstable and possibly
andrewm@0 484 // cause an underrun. Give it ~1ms before going on.
andrewm@0 485 // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed
andrewm@0 486
andrewm@0 487 MOV r2, 1 << 28
andrewm@0 488 MOV r3, GPIO1 + GPIO_SETDATAOUT
andrewm@0 489 SBBO r2, r3, 0, 4
andrewm@0 490
andrewm@0 491 MOV r2, 100000
andrewm@0 492 MCASP_INIT_WAIT:
andrewm@0 493 SUB r2, r2, 1
andrewm@0 494 QBNE MCASP_INIT_WAIT, r2, 0
andrewm@0 495
andrewm@0 496 MOV r2, 1 << 28
andrewm@0 497 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
andrewm@0 498 SBBO r2, r3, 0, 4
andrewm@0 499
andrewm@0 500 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST
andrewm@0 501 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST
andrewm@0 502 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR
andrewm@0 503 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR
andrewm@0 504 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST
andrewm@0 505 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST
andrewm@0 506
andrewm@0 507 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow
andrewm@0 508
andrewm@0 509 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST
andrewm@0 510 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST
andrewm@0 511
andrewm@0 512 // Initialisation
andrewm@12 513 LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP)
andrewm@0 514 MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer
andrewm@12 515 LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize
andrewm@12 516 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels
andrewm@12 517 LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above
andrewm@0 518 MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer
andrewm@12 519 LSL reg_mcasp_buf1, reg_frame_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize
andrewm@0 520 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on
andrewm@0 521 MOV r2, 0
andrewm@0 522 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0
andrewm@0 523
andrewm@0 524 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied
andrewm@0 525 // the first output slot. Send one more word before jumping into the loop.
andrewm@0 526 MCASP_DAC_WAIT_BEFORE_LOOP:
andrewm@0 527 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
andrewm@0 528 QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 529
andrewm@0 530 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00
andrewm@0 531
andrewm@0 532 // Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC
andrewm@0 533 // in sync in terms of which TDM slot we are reading (empirically found that we should throw this away
andrewm@0 534 // rather than keep it and invert the phase)
andrewm@0 535 MCASP_ADC_WAIT_BEFORE_LOOP:
andrewm@0 536 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
andrewm@0 537 QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 538
andrewm@0 539 MCASP_REG_READ_EXT MCASP_RBUF, r2
andrewm@0 540
andrewm@0 541 WRITE_ONE_BUFFER:
andrewm@0 542 // Write a single buffer of DAC samples and read a buffer of ADC samples
andrewm@0 543 // Load starting positions
andrewm@0 544 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer
andrewm@12 545 LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels
andrewm@12 546 LSL reg_adc_current, reg_frame_total, r2
andrewm@12 547 LSL reg_adc_current, reg_adc_current, 2 // N * 2 * 2 * bufsize
andrewm@12 548 ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC
andrewm@0 549 MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
andrewm@12 550 LSL reg_mcasp_adc_current, reg_frame_total, r2 // McASP ADC: starts (N/2)*2*2*bufsize beyond DAC
andrewm@12 551 LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1
andrewm@0 552 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current
andrewm@0 553 MOV reg_frame_current, 0
andrewm@0 554
andrewm@0 555 WRITE_LOOP:
andrewm@12 556 // Write N channels to DAC from successive values in memory
andrewm@12 557 // At the same time, read N channels from ADC
andrewm@0 558 // Unrolled by a factor of 2 to get high and low words
andrewm@0 559 MOV r1, 0
andrewm@0 560 ADC_DAC_LOOP:
andrewm@0 561 QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 562 // Load next 2 SPI DAC samples and store zero in their place
andrewm@0 563 LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4
andrewm@0 564 MOV r2, 0
andrewm@0 565 SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4
andrewm@0 566 ADD reg_dac_current, reg_dac_current, 4
andrewm@0 567 SPI_DAC_LOAD_DONE:
andrewm@0 568
andrewm@0 569 // On even iterations, load two more samples and choose the first one
andrewm@0 570 // On odd iterations, transmit the second of the samples already loaded
andrewm@12 571 // QBBS MCASP_DAC_HIGH_WORD, r1, 1
andrewm@12 572 QBBS MCASP_DAC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 573 MCASP_DAC_LOW_WORD:
andrewm@0 574 // Load next 2 Audio DAC samples and store zero in their place
andrewm@0 575 LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
andrewm@0 576 MOV r2, 0
andrewm@0 577 SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4
andrewm@0 578 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4
andrewm@0 579
andrewm@0 580 // Mask out the low word (first in little endian)
andrewm@0 581 MOV r2, 0xFFFF
andrewm@0 582 AND r7, reg_mcasp_dac_data, r2
andrewm@0 583
andrewm@0 584 QBA MCASP_WAIT_XSTAT
andrewm@0 585 MCASP_DAC_HIGH_WORD:
andrewm@0 586 // Take the high word of the previously loaded data
andrewm@0 587 LSR r7, reg_mcasp_dac_data, 16
andrewm@0 588
andrewm@12 589 // Every 2 channels we send one audio sample; this loop already
andrewm@0 590 // sends exactly two SPI channels.
andrewm@0 591 // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
andrewm@0 592 MCASP_WAIT_XSTAT:
andrewm@0 593 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
andrewm@0 594 QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 595
andrewm@0 596 MCASP_REG_WRITE_EXT MCASP_XBUF, r7
andrewm@0 597
andrewm@0 598 // Same idea with ADC: even iterations, load the sample into the low word, odd
andrewm@0 599 // iterations, load the sample into the high word and store
andrewm@12 600 // QBBS MCASP_ADC_HIGH_WORD, r1, 1
andrewm@12 601 QBBS MCASP_ADC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 602 MCASP_ADC_LOW_WORD:
andrewm@0 603 // Start ADC data at 0
andrewm@0 604 LDI reg_mcasp_adc_data, 0
andrewm@0 605
andrewm@0 606 // Now wait for a received word to become available from the audio ADC
andrewm@0 607 MCASP_WAIT_RSTAT_LOW:
andrewm@0 608 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
andrewm@0 609 QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 610
andrewm@0 611 // Mask low word and store in ADC data register
andrewm@0 612 MCASP_REG_READ_EXT MCASP_RBUF, r3
andrewm@0 613 MOV r2, 0xFFFF
andrewm@0 614 AND reg_mcasp_adc_data, r3, r2
andrewm@0 615 QBA MCASP_ADC_DONE
andrewm@0 616
andrewm@0 617 MCASP_ADC_HIGH_WORD:
andrewm@0 618 // Wait for a received word to become available from the audio ADC
andrewm@0 619 MCASP_WAIT_RSTAT_HIGH:
andrewm@0 620 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
andrewm@0 621 QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 622
andrewm@0 623 // Read data and shift 16 bits to the left (into the high word)
andrewm@0 624 MCASP_REG_READ_EXT MCASP_RBUF, r3
andrewm@0 625 LSL r3, r3, 16
andrewm@0 626 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3
andrewm@0 627
andrewm@0 628 // Now store the result and increment the pointer
andrewm@0 629 SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4
andrewm@0 630 ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4
andrewm@0 631 MCASP_ADC_DONE:
andrewm@0 632 QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 633
andrewm@0 634 // DAC: transmit low word (first in little endian)
andrewm@0 635 MOV r2, 0xFFFF
andrewm@0 636 AND r7, reg_dac_data, r2
andrewm@0 637 LSL r7, r7, AD5668_DATA_OFFSET
andrewm@0 638 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
andrewm@0 639 OR r7, r7, r8
andrewm@0 640 LSL r8, r1, AD5668_ADDRESS_OFFSET
andrewm@0 641 OR r7, r7, r8
andrewm@0 642 DAC_WRITE r7
andrewm@0 643
andrewm@0 644 // Read ADC channels: result is always 2 commands behind
andrewm@0 645 // Start by reading channel 2 (result is channel 0) and go
andrewm@12 646 // to N+2, but masking the channel number to be between 0 and N-1
andrewm@0 647 LDI reg_adc_data, 0
andrewm@12 648 ADD r8, r1, 2
andrewm@12 649 SUB r7, reg_num_channels, 1
andrewm@12 650 AND r8, r8, r7
andrewm@12 651 LSL r8, r8, AD7699_CHANNEL_OFFSET
andrewm@0 652 MOV r7, AD7699_CFG_MASK
andrewm@0 653 OR r7, r7, r8
andrewm@0 654 ADC_WRITE r7, r7
andrewm@0 655
andrewm@0 656 // Mask out only the relevant 16 bits and store in reg_adc_data
andrewm@0 657 MOV r2, 0xFFFF
andrewm@0 658 AND reg_adc_data, r7, r2
andrewm@0 659
andrewm@0 660 // Increment channel index
andrewm@0 661 ADD r1, r1, 1
andrewm@0 662
andrewm@0 663 // DAC: transmit high word (second in little endian)
andrewm@0 664 LSR r7, reg_dac_data, 16
andrewm@0 665 LSL r7, r7, AD5668_DATA_OFFSET
andrewm@0 666 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
andrewm@0 667 OR r7, r7, r8
andrewm@0 668 LSL r8, r1, AD5668_ADDRESS_OFFSET
andrewm@0 669 OR r7, r7, r8
andrewm@0 670 DAC_WRITE r7
andrewm@0 671
andrewm@0 672 // Read ADC channels: result is always 2 commands behind
andrewm@0 673 // Start by reading channel 2 (result is channel 0) and go
andrewm@12 674 // to N+2, but masking the channel number to be between 0 and N-1
andrewm@12 675 LDI reg_adc_data, 0
andrewm@12 676 ADD r8, r1, 2
andrewm@12 677 SUB r7, reg_num_channels, 1
andrewm@12 678 AND r8, r8, r7
andrewm@12 679 LSL r8, r8, AD7699_CHANNEL_OFFSET
andrewm@0 680 MOV r7, AD7699_CFG_MASK
andrewm@0 681 OR r7, r7, r8
andrewm@0 682 ADC_WRITE r7, r7
andrewm@0 683
andrewm@0 684 // Move this result up to the 16 high bits
andrewm@0 685 LSL r7, r7, 16
andrewm@0 686 OR reg_adc_data, reg_adc_data, r7
andrewm@0 687
andrewm@0 688 // Store 2 ADC words in memory
andrewm@0 689 SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
andrewm@0 690 ADD reg_adc_current, reg_adc_current, 4
andrewm@0 691
andrewm@12 692 // Toggle the high/low word for McASP control (since we send one word out of
andrewm@12 693 // 32 bits for each pair of SPI channels)
andrewm@12 694 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
andrewm@12 695
andrewm@12 696 // Repeat 4 times for 8 channels (2 samples per loop, r1 += 1 already happened)
andrewm@12 697 // For 4 or 2 channels, repeat 2 or 1 times, according to flags
andrewm@0 698 ADD r1, r1, 1
andrewm@12 699 QBNE ADC_DAC_LOOP, r1, reg_num_channels
andrewm@0 700 QBA ADC_DAC_LOOP_DONE
andrewm@12 701
andrewm@0 702 SPI_SKIP_WRITE:
andrewm@0 703 // We get here only if the SPI ADC and DAC are disabled
andrewm@0 704 // Just keep the loop going for McASP
andrewm@12 705
andrewm@12 706 // Toggle the high/low word for McASP control (since we send one word out of
andrewm@12 707 // 32 bits for each pair of SPI channels)
andrewm@12 708 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
andrewm@12 709
andrewm@0 710 ADD r1, r1, 2
andrewm@12 711 QBNE ADC_DAC_LOOP, r1, reg_num_channels
andrewm@0 712
andrewm@0 713 ADC_DAC_LOOP_DONE:
andrewm@0 714 // Increment number of frames, see if we have more to write
andrewm@0 715 ADD reg_frame_current, reg_frame_current, 1
andrewm@0 716 QBNE WRITE_LOOP, reg_frame_current, reg_frame_total
andrewm@0 717
andrewm@0 718 WRITE_LOOP_DONE:
andrewm@0 719 // Now done, swap the buffers and do the next one
andrewm@0 720 // Use r2 as a temp register
andrewm@0 721 MOV r2, reg_dac_buf0
andrewm@0 722 MOV reg_dac_buf0, reg_dac_buf1
andrewm@0 723 MOV reg_dac_buf1, r2
andrewm@0 724 MOV r2, reg_mcasp_buf0
andrewm@0 725 MOV reg_mcasp_buf0, reg_mcasp_buf1
andrewm@0 726 MOV reg_mcasp_buf1, r2
andrewm@0 727
andrewm@0 728 // Notify ARM of buffer swap
andrewm@0 729 XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1)
andrewm@0 730 AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit
andrewm@0 731 SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4
andrewm@0 732
andrewm@0 733 // Increment the frame count in the comm buffer (for status monitoring)
andrewm@0 734 LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
andrewm@0 735 ADD r2, r2, reg_frame_total
andrewm@0 736 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
andrewm@0 737
andrewm@0 738 // If LED blink enabled, toggle every 4096 frames
andrewm@0 739 LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4
andrewm@0 740 QBEQ LED_BLINK_DONE, r3, 0
andrewm@0 741 MOV r1, 0x1000
andrewm@0 742 AND r2, r2, r1 // Test (frame count & 4096)
andrewm@0 743 QBEQ LED_BLINK_OFF, r2, 0
andrewm@0 744 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
andrewm@0 745 MOV r1, GPIO_SETDATAOUT
andrewm@0 746 ADD r3, r3, r1 // Address for GPIO set register
andrewm@0 747 SBBO r2, r3, 0, 4 // Set GPIO pin
andrewm@0 748 QBA LED_BLINK_DONE
andrewm@0 749 LED_BLINK_OFF:
andrewm@0 750 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
andrewm@0 751 MOV r1, GPIO_CLEARDATAOUT
andrewm@0 752 ADD r3, r3, r1 // Address for GPIO clear register
andrewm@0 753 SBBO r2, r3, 0, 4 // Clear GPIO pin
andrewm@0 754 LED_BLINK_DONE:
andrewm@0 755
andrewm@0 756 QBBC TESTLOW, reg_flags, FLAG_BIT_BUFFER1
andrewm@0 757 MOV r2, 1 << 28
andrewm@0 758 MOV r3, GPIO1 + GPIO_SETDATAOUT
andrewm@0 759 SBBO r2, r3, 0, 4
andrewm@0 760 QBA TESTDONE
andrewm@0 761 TESTLOW:
andrewm@0 762 MOV r2, 1 << 28
andrewm@0 763 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
andrewm@0 764 SBBO r2, r3, 0, 4
andrewm@0 765 TESTDONE:
andrewm@0 766
andrewm@0 767 // Check if we should finish: flag is zero as long as it should run
andrewm@0 768 LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4
andrewm@0 769 QBEQ WRITE_ONE_BUFFER, r2, 0
andrewm@0 770
andrewm@0 771 CLEANUP:
andrewm@0 772 MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP
andrewm@0 773
andrewm@0 774 // Turn off SPI if enabled
andrewm@0 775 QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 776
andrewm@0 777 MOV r3, SPI_BASE + SPI_CH0CONF
andrewm@0 778 LBBO r2, r3, 0, 4
andrewm@0 779 CLR r2, r2, 13
andrewm@0 780 CLR r2, r2, 27
andrewm@0 781 SBBO r2, r3, 0, 4
andrewm@0 782
andrewm@0 783 MOV r3, SPI_BASE + SPI_CH0CTRL
andrewm@0 784 LBBO r2, r3, 0, 4
andrewm@0 785 CLR r2, r2, 1
andrewm@0 786 SBBO r2, r3, 0, 4
andrewm@0 787 SPI_CLEANUP_DONE:
andrewm@0 788
andrewm@0 789 // Signal the ARM that we have finished
andrewm@0 790 MOV R31.b0, PRU0_ARM_INTERRUPT + 16
andrewm@0 791 HALT