annotate pru_rtaudio.p @ 556:ce391098f321 prerelease tip

THIS PROJECT HAS MOVED TO https://github.com/BelaPlatform/bela
author Giulio Moro <giuliomoro@yahoo.it>
date Sat, 25 Jun 2016 20:21:00 +0100
parents c6a15a8dee02
children
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@45 34 #define PRU0_ARM_INTERRUPT 19 // Interrupt signalling we're done
andrewm@45 35 #define PRU1_ARM_INTERRUPT 20 // Interrupt signalling a block is ready
andrewm@0 36
andrewm@0 37 #define C_ADC_DAC_MEM C24 // PRU0 mem
andrewm@0 38 #ifdef DBOX_CAPE
andrewm@0 39 #define DAC_GPIO GPIO0
andrewm@0 40 #define DAC_CS_PIN (1<<5) // GPIO0:5 = P9 pin 17
andrewm@0 41 #else
andrewm@0 42 #define DAC_GPIO GPIO1
andrewm@0 43 #define DAC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15
andrewm@0 44 #endif
andrewm@0 45 #define DAC_TRM 0 // SPI transmit and receive
andrewm@0 46 #define DAC_WL 32 // Word length
andrewm@0 47 #define DAC_CLK_MODE 1 // SPI mode
andrewm@0 48 #define DAC_CLK_DIV 1 // Clock divider (48MHz / 2^n)
andrewm@0 49 #define DAC_DPE 1 // d0 = receive, d1 = transmit
andrewm@0 50
andrewm@0 51 #define AD5668_COMMAND_OFFSET 24
andrewm@0 52 #define AD5668_ADDRESS_OFFSET 20
andrewm@0 53 #define AD5668_DATA_OFFSET 4
andrewm@0 54 #define AD5668_REF_OFFSET 0
andrewm@0 55
andrewm@0 56 #ifdef DBOX_CAPE
andrewm@0 57 #define ADC_GPIO GPIO1
andrewm@0 58 #define ADC_CS_PIN (1<<16) // GPIO1:16 = P9 pin 15
andrewm@0 59 #else
andrewm@0 60 #define ADC_GPIO GPIO1
andrewm@0 61 #define ADC_CS_PIN (1<<17) // GPIO1:17 = P9 pin 23
andrewm@0 62 #endif
andrewm@0 63 #define ADC_TRM 0 // SPI transmit and receive
andrewm@0 64 #define ADC_WL 16 // Word length
andrewm@0 65 #define ADC_CLK_MODE 0 // SPI mode
andrewm@0 66 #define ADC_CLK_DIV 1 // Clock divider (48MHz / 2^n)
andrewm@0 67 #define ADC_DPE 1 // d0 = receive, d1 = transmit
andrewm@0 68
andrewm@0 69 #define AD7699_CFG_MASK 0xF120 // Mask for config update, unipolar, full BW
andrewm@0 70 #define AD7699_CHANNEL_OFFSET 9 // 7 bits offset of a 14-bit left-justified word
andrewm@0 71 #define AD7699_SEQ_OFFSET 3 // sequencer (0 = disable, 3 = scan all)
andrewm@0 72
andrewm@0 73 #define SHARED_COMM_MEM_BASE 0x00010000 // Location where comm flags are written
andrewm@0 74 #define COMM_SHOULD_STOP 0 // Set to be nonzero when loop should stop
andrewm@0 75 #define COMM_CURRENT_BUFFER 4 // Which buffer we are on
andrewm@0 76 #define COMM_BUFFER_FRAMES 8 // How many frames per buffer
andrewm@0 77 #define COMM_SHOULD_SYNC 12 // Whether to synchronise to an external clock
andrewm@0 78 #define COMM_SYNC_ADDRESS 16 // Which memory address to find the GPIO on
andrewm@0 79 #define COMM_SYNC_PIN_MASK 20 // Which pin to read for the sync
andrewm@0 80 #define COMM_LED_ADDRESS 24 // Which memory address to find the status LED on
andrewm@0 81 #define COMM_LED_PIN_MASK 28 // Which pin to write to change LED
andrewm@0 82 #define COMM_FRAME_COUNT 32 // How many frames have elapse since beginning
andrewm@0 83 #define COMM_USE_SPI 36 // Whether or not to use SPI ADC and DAC
andrewm@12 84 #define COMM_NUM_CHANNELS 40 // Low 2 bits indicate 8 [0x3], 4 [0x1] or 2 [0x0] channels
andrewm@253 85 #define COMM_USE_DIGITAL 44 // Whether or not to use DIGITAL
andrewm@253 86 #define COMM_PRU_NUMBER 48 // Which PRU this code is running on
andrewm@282 87 #define COMM_MUX_CONFIG 52 // Whether to use the mux capelet, and how many channels
andrewm@346 88 #define COMM_MUX_END_CHANNEL 56 // Which mux channel the last buffer ended on
andrewm@346 89
andrewm@282 90 // General constants for McASP peripherals (used for audio codec)
andrewm@0 91 #define MCASP0_BASE 0x48038000
andrewm@0 92 #define MCASP1_BASE 0x4803C000
andrewm@0 93
andrewm@0 94 #define MCASP_PWRIDLESYSCONFIG 0x04
andrewm@0 95 #define MCASP_PFUNC 0x10
andrewm@0 96 #define MCASP_PDIR 0x14
andrewm@0 97 #define MCASP_PDOUT 0x18
andrewm@0 98 #define MCASP_PDSET 0x1C
andrewm@0 99 #define MCASP_PDIN 0x1C
andrewm@0 100 #define MCASP_PDCLR 0x20
andrewm@0 101 #define MCASP_GBLCTL 0x44
andrewm@0 102 #define MCASP_AMUTE 0x48
andrewm@0 103 #define MCASP_DLBCTL 0x4C
andrewm@0 104 #define MCASP_DITCTL 0x50
andrewm@0 105 #define MCASP_RGBLCTL 0x60
andrewm@0 106 #define MCASP_RMASK 0x64
andrewm@0 107 #define MCASP_RFMT 0x68
andrewm@0 108 #define MCASP_AFSRCTL 0x6C
andrewm@0 109 #define MCASP_ACLKRCTL 0x70
andrewm@0 110 #define MCASP_AHCLKRCTL 0x74
andrewm@0 111 #define MCASP_RTDM 0x78
andrewm@0 112 #define MCASP_RINTCTL 0x7C
andrewm@0 113 #define MCASP_RSTAT 0x80
andrewm@0 114 #define MCASP_RSLOT 0x84
andrewm@0 115 #define MCASP_RCLKCHK 0x88
andrewm@0 116 #define MCASP_REVTCTL 0x8C
andrewm@0 117 #define MCASP_XGBLCTL 0xA0
andrewm@0 118 #define MCASP_XMASK 0xA4
andrewm@0 119 #define MCASP_XFMT 0xA8
andrewm@0 120 #define MCASP_AFSXCTL 0xAC
andrewm@0 121 #define MCASP_ACLKXCTL 0xB0
andrewm@0 122 #define MCASP_AHCLKXCTL 0xB4
andrewm@0 123 #define MCASP_XTDM 0xB8
andrewm@0 124 #define MCASP_XINTCTL 0xBC
andrewm@0 125 #define MCASP_XSTAT 0xC0
andrewm@0 126 #define MCASP_XSLOT 0xC4
andrewm@0 127 #define MCASP_XCLKCHK 0xC8
andrewm@0 128 #define MCASP_XEVTCTL 0xCC
andrewm@0 129 #define MCASP_SRCTL0 0x180
andrewm@0 130 #define MCASP_SRCTL1 0x184
andrewm@0 131 #define MCASP_SRCTL2 0x188
andrewm@0 132 #define MCASP_SRCTL3 0x18C
andrewm@0 133 #define MCASP_SRCTL4 0x190
andrewm@0 134 #define MCASP_SRCTL5 0x194
andrewm@0 135 #define MCASP_XBUF0 0x200
andrewm@0 136 #define MCASP_XBUF1 0x204
andrewm@0 137 #define MCASP_XBUF2 0x208
andrewm@0 138 #define MCASP_XBUF3 0x20C
andrewm@0 139 #define MCASP_XBUF4 0x210
andrewm@0 140 #define MCASP_XBUF5 0x214
andrewm@0 141 #define MCASP_RBUF0 0x280
andrewm@0 142 #define MCASP_RBUF1 0x284
andrewm@0 143 #define MCASP_RBUF2 0x288
andrewm@0 144 #define MCASP_RBUF3 0x28C
andrewm@0 145 #define MCASP_RBUF4 0x290
andrewm@0 146 #define MCASP_RBUF5 0x294
andrewm@0 147 #define MCASP_WFIFOCTL 0x1000
andrewm@0 148 #define MCASP_WFIFOSTS 0x1004
andrewm@0 149 #define MCASP_RFIFOCTL 0x1008
andrewm@0 150 #define MCASP_RFIFOSTS 0x100C
andrewm@0 151
giuliomoro@100 152 #define MCASP_XSTAT_XUNDRN_BIT 0 // Bit to test if there was an underrun
andrewm@0 153 #define MCASP_XSTAT_XDATA_BIT 5 // Bit to test for transmit ready
andrewm@0 154 #define MCASP_RSTAT_RDATA_BIT 5 // Bit to test for receive ready
andrewm@0 155
andrewm@0 156 // Constants used for this particular audio setup
andrewm@0 157 #define MCASP_BASE MCASP0_BASE
andrewm@0 158 #ifdef DBOX_CAPE
andrewm@0 159 #define MCASP_SRCTL_X MCASP_SRCTL2 // Ser. 2 is transmitter
andrewm@0 160 #define MCASP_SRCTL_R MCASP_SRCTL0 // Ser. 0 is receiver
andrewm@0 161 #define MCASP_XBUF MCASP_XBUF2
andrewm@0 162 #define MCASP_RBUF MCASP_RBUF0
andrewm@0 163 #else
andrewm@0 164 #define MCASP_SRCTL_X MCASP_SRCTL3 // Ser. 3 is transmitter
andrewm@0 165 #define MCASP_SRCTL_R MCASP_SRCTL2 // Ser. 2 is receiver
andrewm@0 166 #define MCASP_XBUF MCASP_XBUF3
andrewm@0 167 #define MCASP_RBUF MCASP_RBUF2
andrewm@0 168 #endif
andrewm@0 169
andrewm@0 170 #define MCASP_PIN_AFSX (1 << 28)
andrewm@0 171 #define MCASP_PIN_AHCLKX (1 << 27)
andrewm@0 172 #define MCASP_PIN_ACLKX (1 << 26)
andrewm@0 173 #define MCASP_PIN_AMUTE (1 << 25) // Also, 0 to 3 are XFR0 to XFR3
andrewm@0 174
andrewm@0 175 #ifdef DBOX_CAPE
andrewm@0 176 #define MCASP_OUTPUT_PINS MCASP_PIN_AHCLKX | (1 << 2) // AHCLKX and AXR2 outputs
andrewm@0 177 #else
andrewm@0 178 #define MCASP_OUTPUT_PINS (1 << 3) // Which pins are outputs
andrewm@0 179 #endif
andrewm@0 180
andrewm@0 181 #define MCASP_DATA_MASK 0xFFFF // 16 bit data
andrewm@0 182 #define MCASP_DATA_FORMAT 0x807C // MSB first, 0 bit delay, 16 bits, CFG bus, ROR 16bits
andrewm@0 183
andrewm@12 184 #define C_MCASP_MEM C28 // Shared PRU mem
andrewm@0 185
andrewm@0 186 // Flags for the flags register
andrewm@0 187 #define FLAG_BIT_BUFFER1 0
andrewm@0 188 #define FLAG_BIT_USE_SPI 1
andrewm@12 189 #define FLAG_BIT_MCASP_HWORD 2 // Whether we are on the high word for McASP transmission
andrewm@282 190 #define FLAG_BIT_USE_DIGITAL 3
andrewm@282 191
andrewm@282 192 #define FLAG_BIT_MUX_CONFIG0 8 // Mux capelet configuration:
andrewm@282 193 #define FLAG_BIT_MUX_CONFIG1 9 // 00 = off, 01 = 2 ch., 10 = 4 ch., 11 = 8 ch.
andrewm@282 194 #define FLAG_MASK_MUX_CONFIG 0x0300
andrewm@346 195
andrewm@0 196 // Registers used throughout
andrewm@0 197
andrewm@0 198 // r1, r2, r3 are used for temporary storage
giuliomoro@19 199 #define MEM_DIGITAL_BASE 0x11000 //Base address for DIGITAL : Shared RAM + 0x400
giuliomoro@19 200 #define MEM_DIGITAL_BUFFER1_OFFSET 0x400 //Start pointer to DIGITAL_BUFFER1, which is 256 words after.
giuliomoro@16 201 // 256 is the maximum number of frames allowed
giuliomoro@16 202
giuliomoro@40 203 #define reg_digital_current r6 // Pointer to current storage location of DIGITAL
andrewm@12 204 #define reg_num_channels r9 // Number of SPI ADC/DAC channels to use
andrewm@0 205 #define reg_frame_current r10 // Current frame count in SPI ADC/DAC transfer
andrewm@0 206 #define reg_frame_total r11 // Total frame count for SPI ADC/DAC
andrewm@0 207 #define reg_dac_data r12 // Current dword for SPI DAC
andrewm@0 208 #define reg_adc_data r13 // Current dword for SPI ADC
andrewm@0 209 #define reg_mcasp_dac_data r14 // Current dword for McASP DAC
andrewm@0 210 #define reg_mcasp_adc_data r15 // Current dword for McASP ADC
andrewm@0 211 #define reg_dac_buf0 r16 // Start pointer to SPI DAC buffer 0
andrewm@0 212 #define reg_dac_buf1 r17 // Start pointer to SPI DAC buffer 1
andrewm@0 213 #define reg_dac_current r18 // Pointer to current storage location of SPI DAC
andrewm@0 214 #define reg_adc_current r19 // Pointer to current storage location of SPI ADC
andrewm@0 215 #define reg_mcasp_buf0 r20 // Start pointer to McASP DAC buffer 0
andrewm@0 216 #define reg_mcasp_buf1 r21 // Start pointer to McASP DAC buffer 1
andrewm@0 217 #define reg_mcasp_dac_current r22 // Pointer to current storage location of McASP DAC
andrewm@0 218 #define reg_mcasp_adc_current r23 // Pointer to current storage location of McASP ADC
andrewm@0 219 #define reg_flags r24 // Buffer ID (0 and 1) and other flags
andrewm@0 220 #define reg_comm_addr r25 // Memory address for communicating with ARM
andrewm@0 221 #define reg_spi_addr r26 // Base address for SPI
andrewm@0 222 // r27, r28 used in macros
andrewm@0 223 #define reg_mcasp_addr r29 // Base address for McASP
andrewm@282 224 #define reg_pru1_mux_pins r30 // Register mapped directly to P8 pins (PRU1 only)
andrewm@0 225
giuliomoro@16 226 //0 P8_07 36 0x890/090 66 gpio2[2]
giuliomoro@16 227 //1 P8_08 37 0x894/094 67 gpio2[3]
giuliomoro@16 228 //2 P8_09 39 0x89c/09c 69 gpio2[5]
giuliomoro@16 229 //3 P8_10 38 0x898/098 68 gpio2[4]
giuliomoro@16 230 //4 P8_11 13 0x834/034 45 gpio1[13]
giuliomoro@16 231 //5 P8_12 12 0x830/030 44 gpio1[12]
giuliomoro@16 232 //6 P9_12 30 0x878/078 60 gpio1[28]
giuliomoro@16 233 //7 P9_14 18 0x848/048 50 gpio1[18]
giuliomoro@16 234 //8 P8_15 15 0x83c/03c 47 gpio1[15]
giuliomoro@16 235 //9 P8_16 14 0x838/038 46 gpio1[14]
giuliomoro@16 236 //10 P9_16 19 0x84c/04c 51 gpio1[19]
giuliomoro@16 237 //11 P8_18 35 0x88c/08c 65 gpio2[1]
giuliomoro@16 238 //12 P8_27 56 0x8e0/0e0 86 gpio2[22]
giuliomoro@16 239 //13 P8_28 58 0x8e8/0e8 88 gpio2[24]
giuliomoro@16 240 //14 P8_29 57 0x8e4/0e4 87 gpio2[23]
giuliomoro@16 241 //15 P8_30 59 0x8ec/0ec 89 gpio2[25]
giuliomoro@16 242
giuliomoro@16 243 //generic GPIOs constants
giuliomoro@16 244 //#define GPIO1 0x4804c000
giuliomoro@16 245 #define GPIO2 0x481ac000
giuliomoro@16 246 //#define GPIO_CLEARDATAOUT 0x190 //SETDATAOUT is CLEARDATAOUT+4
giuliomoro@16 247 #define GPIO_OE 0x134
giuliomoro@16 248 #define GPIO_DATAIN 0x138
giuliomoro@16 249
giuliomoro@16 250 .macro READ_GPIO_BITS
giuliomoro@19 251 .mparam gpio_data, gpio_num_bit, digital_bit, digital
giuliomoro@19 252 QBBC DONE, digital, digital_bit //if the pin is set as an output, nothing to do here
giuliomoro@16 253 QBBC CLEAR, gpio_data, gpio_num_bit
giuliomoro@19 254 SET digital, digital_bit+16
giuliomoro@16 255 QBA DONE
giuliomoro@16 256 CLEAR:
giuliomoro@19 257 CLR digital, digital_bit+16
giuliomoro@16 258 QBA DONE
giuliomoro@16 259 DONE:
giuliomoro@16 260 .endm
giuliomoro@16 261
giuliomoro@16 262 .macro SET_GPIO_BITS
giuliomoro@19 263 .mparam gpio_oe, gpio_setdataout, gpio_cleardataout, gpio_num_bit, digital_bit, digital //sets the bits in GPIO_OE, GPIO_SETDATAOUT and GPIO_CLEARDATAOUT
giuliomoro@16 264 //Remember that the GPIO_OE Output data enable register behaves as follows for each bit:
giuliomoro@16 265 //0 = The corresponding GPIO pin is configured as an output.
giuliomoro@16 266 //1 = The corresponding GPIO pin is configured as an input.
giuliomoro@19 267 QBBS SETINPUT, digital, digital_bit
giuliomoro@16 268 CLR gpio_oe, gpio_num_bit //if it is an output, configure pin as output
giuliomoro@19 269 QBBC CLEARDATAOUT, digital, digital_bit+16 // check the output value. If it is 0, branch
giuliomoro@16 270 SET gpio_setdataout, gpio_num_bit //if it is 1, set output to high
giuliomoro@16 271 QBA DONE
giuliomoro@16 272 CLEARDATAOUT:
giuliomoro@16 273 SET gpio_cleardataout, gpio_num_bit // set output to low
giuliomoro@16 274 QBA DONE
giuliomoro@16 275 SETINPUT: //if it is an input, set the relevant bit
giuliomoro@16 276 SET gpio_oe, gpio_num_bit
giuliomoro@16 277 QBA DONE
giuliomoro@16 278 DONE:
giuliomoro@16 279 .endm
giuliomoro@16 280
giuliomoro@16 281 QBA START // when first starting, go to START, skipping this section.
giuliomoro@16 282
giuliomoro@19 283 DIGITAL:
giuliomoro@39 284 //IMPORTANT: do NOT use r28 in this macro, as it contains the return address for JAL
giuliomoro@39 285 //r27 is now the input word passed in render(), one word per frame
giuliomoro@16 286 //[31:16]: data(1=high, 0=low), [15:0]: direction (0=output, 1=input) )
giuliomoro@39 287
giuliomoro@39 288
giuliomoro@16 289 //Preparing the gpio_oe, gpio_cleardataout and gpio_setdataout for each module
giuliomoro@39 290 //r2 will hold GPIO1_OE
giuliomoro@39 291 //load current status of GPIO_OE in r2
giuliomoro@39 292 MOV r2, GPIO1 | GPIO_OE
giuliomoro@26 293 //it takes 190ns to go through the next instruction
giuliomoro@39 294 LBBO r2, r2, 0, 4
giuliomoro@16 295 //GPIO1-start
giuliomoro@16 296 //process oe and datain and prepare dataout for GPIO1
giuliomoro@39 297 //r7 will contain GPIO1_CLEARDATAOUT
giuliomoro@39 298 //r8 will contain GPIO1_SETDATAOUT
giuliomoro@39 299 MOV r8, 0
giuliomoro@39 300 MOV r7, 0
giuliomoro@39 301 //map GPIO_ANALOG to gpio1 pins,
giuliomoro@39 302 //r2 is gpio1_oe, r8 is gpio1_setdataout, r7 is gpio1_cleardataout, r27 is the input word
giuliomoro@39 303 //the following operations will read from r27 and update r2,r7,r8
giuliomoro@39 304 SET_GPIO_BITS r2, r8, r7, 13, 4, r27
giuliomoro@39 305 SET_GPIO_BITS r2, r8, r7, 12, 5, r27
giuliomoro@39 306 SET_GPIO_BITS r2, r8, r7, 28, 6, r27
giuliomoro@39 307 SET_GPIO_BITS r2, r8, r7, 18, 7, r27
giuliomoro@39 308 SET_GPIO_BITS r2, r8, r7, 15, 8, r27
giuliomoro@39 309 SET_GPIO_BITS r2, r8, r7, 14, 9, r27
giuliomoro@39 310 SET_GPIO_BITS r2, r8, r7, 19, 10, r27
giuliomoro@16 311 //set the output enable register for gpio1.
giuliomoro@39 312 MOV r3, GPIO1 | GPIO_OE //use r3 as a temp register
giuliomoro@39 313 SBBO r2, r3, 0, 4 //takes two cycles (10ns)
giuliomoro@16 314 //GPIO1-end
giuliomoro@39 315 // r2 is now unused
giuliomoro@16 316
giuliomoro@16 317 //GPIO2-start
giuliomoro@39 318 //r3 will hold GPIO1_OE
giuliomoro@39 319 //load current status of GPIO_OE in r3
giuliomoro@39 320 MOV r3, GPIO2 | GPIO_OE
giuliomoro@26 321 //it takes 200ns to go through the next instructions
giuliomoro@39 322 LBBO r3, r3, 0, 4
giuliomoro@16 323 //process oe and datain and prepare dataout for GPIO2
giuliomoro@39 324 //r4 will contain GPIO2_CLEARDATAOUT
giuliomoro@39 325 //r5 will contain GPIO2_SETDATAOUT
giuliomoro@39 326 MOV r5, 0
giuliomoro@39 327 MOV r4, 0
giuliomoro@39 328 //map GPIO_ANALOG to gpio2 pins
giuliomoro@39 329 //r3 is gpio2_oe, r5 is gpio2_setdataout, r4 is gpio2_cleardataout, r27 is the input word
giuliomoro@39 330 //the following operations will read from r27 and update r3,r4,r5
giuliomoro@39 331 SET_GPIO_BITS r3, r5, r4, 2, 0, r27
giuliomoro@39 332 SET_GPIO_BITS r3, r5, r4, 3, 1, r27
giuliomoro@39 333 SET_GPIO_BITS r3, r5, r4, 5, 2, r27
giuliomoro@39 334 SET_GPIO_BITS r3, r5, r4, 4, 3, r27
giuliomoro@39 335 SET_GPIO_BITS r3, r5, r4, 1, 11, r27
giuliomoro@39 336 SET_GPIO_BITS r3, r5, r4, 22, 12, r27
giuliomoro@39 337 SET_GPIO_BITS r3, r5, r4, 24, 13, r27
giuliomoro@39 338 SET_GPIO_BITS r3, r5, r4, 23, 14, r27
giuliomoro@39 339 SET_GPIO_BITS r3, r5, r4, 25, 15, r27
giuliomoro@16 340 //set the output enable register for gpio2.
giuliomoro@39 341 MOV r2, GPIO2 | GPIO_OE //use r2 as a temp registerp
giuliomoro@39 342 SBBO r3, r2, 0, 4 //takes two cycles (10ns)
giuliomoro@16 343 //GPIO2-end
giuliomoro@39 344 //r3 is now unused
giuliomoro@16 345
giuliomoro@39 346 //load current inputs in r2, r3
giuliomoro@39 347 //r2 will contain GPIO1_DATAIN
giuliomoro@39 348 //r3 will contain GPIO2_DATAIN
giuliomoro@39 349 //load the memory locations
giuliomoro@39 350 MOV r2, GPIO1 | GPIO_DATAIN
giuliomoro@39 351 MOV r3, GPIO2 | GPIO_DATAIN
giuliomoro@26 352 //takes 375 nns to go through the next two instructions
giuliomoro@39 353 //read the datain
giuliomoro@39 354 LBBO r2, r2, 0, 4
giuliomoro@39 355 LBBO r3, r3, 0, 4
giuliomoro@39 356 //now read from r2 and r3 only the channels that are set as input in the lower word of r27
giuliomoro@39 357 // and set their value in the high word of r27
giuliomoro@39 358 //GPIO1
giuliomoro@39 359 READ_GPIO_BITS r2, 13, 4, r27
giuliomoro@39 360 READ_GPIO_BITS r2, 12, 5, r27
giuliomoro@39 361 READ_GPIO_BITS r2, 28, 6, r27
giuliomoro@39 362 READ_GPIO_BITS r2, 18, 7, r27
giuliomoro@39 363 READ_GPIO_BITS r2, 15, 8, r27
giuliomoro@39 364 READ_GPIO_BITS r2, 14, 9, r27
giuliomoro@39 365 READ_GPIO_BITS r2, 19, 10, r27
giuliomoro@39 366 //GPIO2
giuliomoro@39 367 READ_GPIO_BITS r3, 2, 0, r27
giuliomoro@39 368 READ_GPIO_BITS r3, 3, 1, r27
giuliomoro@39 369 READ_GPIO_BITS r3, 5, 2, r27
giuliomoro@39 370 READ_GPIO_BITS r3, 4, 3, r27
giuliomoro@39 371 READ_GPIO_BITS r3, 1, 11, r27
giuliomoro@39 372 READ_GPIO_BITS r3, 22, 12, r27
giuliomoro@39 373 READ_GPIO_BITS r3, 24, 13, r27
giuliomoro@39 374 READ_GPIO_BITS r3, 23, 14, r27
giuliomoro@39 375 READ_GPIO_BITS r3, 25, 15, r27
giuliomoro@39 376 //r2, r3 are now unused
giuliomoro@16 377
giuliomoro@16 378 //now all the setdataout and cleardataout are ready to be written to the GPIO register.
giuliomoro@39 379 //CLEARDATAOUT and SETDATAOUT are consecutive positions in memory, so we just write 8 bytes to CLEARDATAOUT.
giuliomoro@39 380 //We can do this because we chose cleardata and setdata registers for a given GPIO to be consecutive
giuliomoro@16 381 //load the memory addresses to be written to
giuliomoro@39 382 MOV r2, GPIO1 | GPIO_CLEARDATAOUT //use r2 as a temp register
giuliomoro@39 383 MOV r3, GPIO2 | GPIO_CLEARDATAOUT //use r3 as a temp register
giuliomoro@16 384 //write 8 bytes for each GPIO
giuliomoro@39 385 //takes 30ns in total to go through the following two instructions
giuliomoro@39 386 SBBO r7, r2, 0, 8 //store r7 and r8 in GPIO1_CLEARDATAOUT and GPIO1_SETDATAOUT
giuliomoro@39 387 //takes 145ns to be effective when going low, 185ns when going high
giuliomoro@39 388 SBBO r4, r3, 0, 8 //store r4 and r5 in GPIO2_CLEARDATAOUT and GPIO2_SETDATAOUT
giuliomoro@39 389 //takes 95ns to be effective when going low, 130ns when going high
giuliomoro@16 390 //reversing the order of the two lines above will swap the performances between the GPIO modules
giuliomoro@16 391 //i.e.: the first line will always take 145ns/185ns and the second one will always take 95ns/130ns,
giuliomoro@16 392 //regardless of whether the order is gpio1-gpio2 or gpio2-gpio1
giuliomoro@39 393 JMP r28.w0 // go back to ADC_WRITE_AND_PROCESS_GPIO
giuliomoro@16 394
giuliomoro@39 395 .macro HANG //useful for debugging
giuliomoro@188 396 DALOOP:
giuliomoro@102 397 set r30.t14
giuliomoro@102 398 clr r30.t14
giuliomoro@38 399 QBA DALOOP
giuliomoro@38 400 .endm
giuliomoro@39 401
andrewm@0 402 // Bring CS line low to write to DAC
andrewm@0 403 .macro DAC_CS_ASSERT
giuliomoro@102 404 MOV r27, DAC_CS_PIN
giuliomoro@102 405 MOV r28, DAC_GPIO + GPIO_CLEARDATAOUT
giuliomoro@102 406 SBBO r27, r28, 0, 4
andrewm@0 407 .endm
andrewm@0 408
andrewm@0 409 // Bring CS line high at end of DAC transaction
andrewm@0 410 .macro DAC_CS_UNASSERT
giuliomoro@102 411 MOV r27, DAC_CS_PIN
giuliomoro@102 412 MOV r28, DAC_GPIO + GPIO_SETDATAOUT
giuliomoro@102 413 SBBO r27, r28, 0, 4
andrewm@0 414 .endm
andrewm@0 415
andrewm@0 416 // Write to DAC TX register
andrewm@0 417 .macro DAC_TX
andrewm@0 418 .mparam data
andrewm@0 419 SBBO data, reg_spi_addr, SPI_CH0TX, 4
andrewm@0 420 .endm
andrewm@0 421
andrewm@0 422 // Wait for SPI to finish (uses RXS indicator)
andrewm@0 423 .macro DAC_WAIT_FOR_FINISH
andrewm@0 424 LOOP:
giuliomoro@102 425 LBBO r27, reg_spi_addr, SPI_CH0STAT, 4
giuliomoro@102 426 QBBC LOOP, r27, 0
andrewm@0 427 .endm
andrewm@0 428
andrewm@0 429 // Read the RX word to clear
andrewm@0 430 .macro DAC_DISCARD_RX
giuliomoro@102 431 LBBO r27, reg_spi_addr, SPI_CH0RX, 4
andrewm@0 432 .endm
andrewm@0 433
andrewm@0 434 // Complete DAC write with chip select
andrewm@0 435 .macro DAC_WRITE
andrewm@0 436 .mparam reg
giuliomoro@102 437 DAC_CS_ASSERT
giuliomoro@102 438 DAC_TX reg
giuliomoro@102 439 DAC_WAIT_FOR_FINISH
giuliomoro@102 440 DAC_CS_UNASSERT
giuliomoro@102 441 DAC_DISCARD_RX
andrewm@0 442 .endm
andrewm@0 443
andrewm@346 444 // Transform channel order on DAC
andrewm@346 445 // (in) 01234567 --> (out) 64201357
andrewm@346 446 // This is to make the pin order on the Bela cape
andrewm@346 447 // make sense
andrewm@346 448 .macro DAC_CHANNEL_REORDER
andrewm@346 449 .mparam out, in
andrewm@346 450 QBBS DAC_CHANNEL_REORDER_HIGH, in, 2
andrewm@346 451 // Input channels 0,1,2,3 --> 6,4,2,0
andrewm@346 452 // out = (3 - in) << 1
andrewm@346 453 XOR out, in, 0x03
andrewm@346 454 LSL out, out, 1
andrewm@346 455 QBA DAC_CHANNEL_REORDER_DONE
andrewm@346 456 DAC_CHANNEL_REORDER_HIGH:
andrewm@346 457 // Input channels 4,5,6,7 --> 1,3,5,7
andrewm@346 458 // out = ((in & 0x03) << 1) + 1
andrewm@346 459 AND out, in, 0x03
andrewm@346 460 LSL out, out, 1
andrewm@346 461 ADD out, out, 1
andrewm@346 462 DAC_CHANNEL_REORDER_DONE:
andrewm@346 463 .endm
andrewm@346 464
andrewm@0 465 // Bring CS line low to write to ADC
andrewm@0 466 .macro ADC_CS_ASSERT
giuliomoro@102 467 MOV r27, ADC_CS_PIN
giuliomoro@102 468 MOV r28, ADC_GPIO + GPIO_CLEARDATAOUT
giuliomoro@102 469 SBBO r27, r28, 0, 4
andrewm@0 470 .endm
andrewm@0 471
andrewm@0 472 // Bring CS line high at end of ADC transaction
andrewm@0 473 .macro ADC_CS_UNASSERT
giuliomoro@102 474 MOV r27, ADC_CS_PIN
giuliomoro@102 475 MOV r28, ADC_GPIO + GPIO_SETDATAOUT
giuliomoro@102 476 SBBO r27, r28, 0, 4
andrewm@0 477 .endm
andrewm@0 478
andrewm@0 479 // Write to ADC TX register
andrewm@0 480 .macro ADC_TX
andrewm@0 481 .mparam data
giuliomoro@102 482 SBBO data, reg_spi_addr, SPI_CH1TX, 4
andrewm@0 483 .endm
andrewm@0 484
andrewm@0 485 // Wait for SPI to finish (uses RXS indicator)
andrewm@0 486 .macro ADC_WAIT_FOR_FINISH
andrewm@0 487 LOOP:
giuliomoro@102 488 LBBO r27, reg_spi_addr, SPI_CH1STAT, 4
giuliomoro@102 489 QBBC LOOP, r27, 0
andrewm@0 490 .endm
andrewm@0 491
andrewm@0 492 // Read the RX word to clear; store output
andrewm@0 493 .macro ADC_RX
andrewm@0 494 .mparam data
giuliomoro@102 495 LBBO data, reg_spi_addr, SPI_CH1RX, 4
andrewm@0 496 .endm
andrewm@0 497
andrewm@0 498 // Complete ADC write+read with chip select
andrewm@0 499 .macro ADC_WRITE
andrewm@0 500 .mparam in, out
giuliomoro@102 501 ADC_CS_ASSERT
giuliomoro@102 502 ADC_TX in
giuliomoro@102 503 ADC_WAIT_FOR_FINISH
giuliomoro@102 504 ADC_RX out
giuliomoro@102 505 ADC_CS_UNASSERT
andrewm@0 506 .endm
andrewm@0 507
giuliomoro@19 508 // Complete ADC write+read with chip select and also performs IO for digital
giuliomoro@16 509 .macro ADC_WRITE_GPIO
giuliomoro@16 510 .mparam in, out, do_gpio
giuliomoro@102 511 ADC_CS_ASSERT
giuliomoro@102 512 ADC_TX in
giuliomoro@102 513 QBBC GPIO_DONE, reg_flags, FLAG_BIT_USE_DIGITAL //skip if DIGITAL is disabled
giuliomoro@188 514 QBLT CASE_4_OR_8_CHANNELS, reg_num_channels, 2
giuliomoro@188 515 CASE_2_CHANNELS:
giuliomoro@188 516 AND r27, reg_frame_current, 0x1
giuliomoro@188 517 QBNE GPIO_DONE, r27, 0
giuliomoro@188 518 JMP DO_GPIO
giuliomoro@188 519 CASE_4_OR_8_CHANNELS:
giuliomoro@102 520 AND r27, do_gpio, 0x3 // only do a DIGITAL every 2 SPI I/O
giuliomoro@102 521 QBNE GPIO_DONE, r27, 0
giuliomoro@188 522 DO_GPIO:
giuliomoro@16 523 //from here to GPIO_DONE takes 1.8us, while usually ADC_WAIT_FOR_FINISH only waits for 1.14us.
giuliomoro@19 524 //TODO: it would be better to split the DIGITAL stuff in two parts:
giuliomoro@16 525 //- one taking place during DAC_WRITE which sets the GPIO_OE
giuliomoro@16 526 //- and the other during ADC_WRITE which actually reads DATAIN and writes CLEAR/SET DATAOUT
giuliomoro@39 527 //r27 is actually r27, so do not use r27 from here to ...
giuliomoro@102 528 LBBO r27, reg_digital_current, 0, 4
giuliomoro@102 529 JAL r28.w0, DIGITAL // note that this is not called as a macro, but with JAL. r28 will contain the return address
giuliomoro@102 530 SBBO r27, reg_digital_current, 0, 4
giuliomoro@16 531 //..here you can start using r27 again
giuliomoro@102 532 ADD reg_digital_current, reg_digital_current, 4 //increment pointer
giuliomoro@16 533 GPIO_DONE:
giuliomoro@102 534 ADC_WAIT_FOR_FINISH
giuliomoro@102 535 ADC_RX out
giuliomoro@102 536 ADC_CS_UNASSERT
giuliomoro@16 537 .endm
giuliomoro@16 538
andrewm@0 539 // Write a McASP register
andrewm@0 540 .macro MCASP_REG_WRITE
andrewm@0 541 .mparam reg, value
giuliomoro@102 542 MOV r27, value
giuliomoro@102 543 SBBO r27, reg_mcasp_addr, reg, 4
andrewm@0 544 .endm
andrewm@0 545
andrewm@0 546 // Write a McASP register beyond the 0xFF boundary
andrewm@0 547 .macro MCASP_REG_WRITE_EXT
andrewm@0 548 .mparam reg, value
giuliomoro@102 549 MOV r27, value
giuliomoro@102 550 MOV r28, reg
giuliomoro@102 551 ADD r28, reg_mcasp_addr, r28
giuliomoro@102 552 SBBO r27, r28, 0, 4
andrewm@0 553 .endm
andrewm@0 554
andrewm@0 555 // Read a McASP register
andrewm@0 556 .macro MCASP_REG_READ
andrewm@0 557 .mparam reg, value
giuliomoro@102 558 LBBO value, reg_mcasp_addr, reg, 4
andrewm@0 559 .endm
andrewm@0 560
andrewm@0 561 // Read a McASP register beyond the 0xFF boundary
andrewm@0 562 .macro MCASP_REG_READ_EXT
andrewm@0 563 .mparam reg, value
giuliomoro@102 564 MOV r28, reg
giuliomoro@102 565 ADD r28, reg_mcasp_addr, r28
giuliomoro@102 566 LBBO value, r28, 0, 4
andrewm@0 567 .endm
andrewm@0 568
andrewm@0 569 // Set a bit and wait for it to come up
andrewm@0 570 .macro MCASP_REG_SET_BIT_AND_POLL
andrewm@0 571 .mparam reg, mask
giuliomoro@102 572 MOV r27, mask
giuliomoro@102 573 LBBO r28, reg_mcasp_addr, reg, 4
giuliomoro@102 574 OR r28, r28, r27
giuliomoro@102 575 SBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 576 POLL:
giuliomoro@102 577 LBBO r28, reg_mcasp_addr, reg, 4
giuliomoro@102 578 AND r28, r28, r27
giuliomoro@102 579 QBEQ POLL, r28, 0
andrewm@0 580 .endm
andrewm@282 581
andrewm@282 582 // Multiplexer Capelet: Increment channel on muxes 0-3
andrewm@282 583 .macro MUX_INCREMENT_0_TO_3
andrewm@282 584 MOV r28, FLAG_MASK_MUX_CONFIG
andrewm@282 585 AND r28, reg_flags, r28 // Check flags
andrewm@282 586 QBEQ DONE, r28, 0 // Skip if disabled
andrewm@282 587 LSR r28, r28, FLAG_BIT_MUX_CONFIG0
andrewm@282 588 AND r27, reg_pru1_mux_pins, 0x07 // Current mux channel in r30 bits 2-0
andrewm@282 589 ADD r27, r27, 1 // Increment channel
andrewm@282 590 AND r27, r27, 0x07 // Mask to 8 channels
andrewm@282 591 QBEQ UPDATE, r28, 0x03
andrewm@282 592 AND r27, r27, 0x03 // Mask to 4 channels
andrewm@282 593 QBEQ UPDATE, r28, 0x02
andrewm@282 594 AND r27, r27, 0x01 // Mask to 2 channels
andrewm@282 595 UPDATE:
andrewm@282 596 MOV r28, 0xFFFFFFF8
andrewm@282 597 AND r28, reg_pru1_mux_pins, r28 // Mask out low 3 bits of r30
andrewm@282 598 OR r28, r28, r27 // Combine with new value
andrewm@282 599 MOV reg_pru1_mux_pins, r28 // Move back to r30 to propagate to pins
andrewm@282 600 DONE:
andrewm@282 601 .endm
andrewm@283 602
andrewm@283 603 // Multiplexer Capelet: Increment channel on muxes 4-7
andrewm@283 604 .macro MUX_INCREMENT_4_TO_7
andrewm@283 605 MOV r28, FLAG_MASK_MUX_CONFIG
andrewm@283 606 AND r28, reg_flags, r28 // Check flags
andrewm@283 607 QBEQ DONE, r28, 0 // Skip if disabled
andrewm@283 608 LSR r28, r28, FLAG_BIT_MUX_CONFIG0
andrewm@283 609 AND r27, reg_pru1_mux_pins, 0x38 // Current mux channel in r30 bits 5-3
andrewm@283 610 ADD r27, r27, 8 // Increment channel (+1 LSB starting at bit 3)
andrewm@283 611 AND r27, r27, 0x38 // Mask to 8 channels
andrewm@283 612 QBEQ UPDATE, r28, 0x03
andrewm@283 613 AND r27, r27, 0x18 // Mask to 4 channels
andrewm@283 614 QBEQ UPDATE, r28, 0x02
andrewm@283 615 AND r27, r27, 0x08 // Mask to 2 channels
andrewm@283 616 UPDATE:
andrewm@283 617 MOV r28, 0xFFFFFFC7
andrewm@283 618 AND r28, reg_pru1_mux_pins, r28 // Mask out bits 5-3 of r30
andrewm@283 619 OR r28, r28, r27 // Combine with new value
andrewm@283 620 MOV reg_pru1_mux_pins, r28 // Move back to r30 to propagate to pins
andrewm@283 621 DONE:
andrewm@283 622 .endm
andrewm@283 623
andrewm@282 624
andrewm@0 625 START:
andrewm@253 626 // Load useful registers for addressing SPI
andrewm@253 627 MOV reg_comm_addr, SHARED_COMM_MEM_BASE
andrewm@253 628 MOV reg_spi_addr, SPI_BASE
andrewm@253 629 MOV reg_mcasp_addr, MCASP_BASE
andrewm@253 630
andrewm@253 631 // Find out which PRU we are running on
andrewm@253 632 // This affects the following offsets
andrewm@253 633 MOV r0, 0x24000 // PRU1 control register offset
andrewm@253 634 LBBO r2, reg_comm_addr, COMM_PRU_NUMBER, 4
andrewm@253 635 QBEQ PRU_NUMBER_CHECK_DONE, r2, 1
andrewm@253 636 MOV r0, 0x22000 // PRU0 control register offset
andrewm@253 637 PRU_NUMBER_CHECK_DONE:
andrewm@253 638
giuliomoro@102 639 // Set up c24 and c25 offsets with CTBIR register
giuliomoro@102 640 // Thus C24 points to start of PRU0 RAM
andrewm@253 641 OR r3, r0, 0x20 // CTBIR0
giuliomoro@102 642 MOV r2, 0
giuliomoro@102 643 SBBO r2, r3, 0, 4
andrewm@0 644
giuliomoro@102 645 // Set up c28 pointer offset for shared PRU RAM
andrewm@253 646 OR r3, r0, 0x28 // CTPPR0
giuliomoro@102 647 MOV r2, 0x00000120 // To get address 0x00012000
giuliomoro@102 648 SBBO r2, r3, 0, 4
andrewm@0 649
giuliomoro@102 650 // Set ARM such that PRU can write to registers
giuliomoro@102 651 LBCO r0, C4, 4, 4
giuliomoro@102 652 CLR r0, r0, 4
giuliomoro@102 653 SBCO r0, C4, 4, 4
andrewm@0 654
giuliomoro@102 655 // Clear flags
giuliomoro@102 656 MOV reg_flags, 0
giuliomoro@102 657 // Default number of channels in case SPI disabled
giuliomoro@102 658 LDI reg_num_channels, 8
andrewm@0 659
giuliomoro@102 660 // Find out whether we should use DIGITAL
giuliomoro@102 661 LBBO r2, reg_comm_addr, COMM_USE_DIGITAL, 4
giuliomoro@102 662 QBEQ DIGITAL_INIT_DONE, r2, 0 // if we use digital
giuliomoro@102 663 SET reg_flags, reg_flags, FLAG_BIT_USE_DIGITAL
giuliomoro@38 664 /* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started.
giuliomoro@38 665 Will leave it here for future reference
giuliomoro@38 666 DIGITAL_INIT: //set the digital buffer to 0x0000ffff (all inputs), to prevent unwanted high outputs
giuliomoro@38 667 //the loop is unrolled by a factor of four just to take advantage of the speed of SBBO on larger byte bursts, but there is no real need for it
giuliomoro@102 668 MOV r2, 0x0000ffff //value to store. 0x0000ffff means all inputs
giuliomoro@102 669 MOV r3, MEM_DIGITAL_BASE //start of the digital buffer
giuliomoro@102 670 MOV r4, MEM_DIGITAL_BASE+2*MEM_DIGITAL_BUFFER1_OFFSET //end of the digital buffer
giuliomoro@38 671 DIGITAL_INIT_BUFFER_LOOP:
giuliomoro@102 672 SBBO r2, r3, 0, 4
giuliomoro@102 673 ADD r3, r3, 4 //increment pointer
giuliomoro@102 674 QBGT DIGITAL_INIT_BUFFER_LOOP, r3, r4 //loop until we reach the end of the buffer
giuliomoro@38 675 */
giuliomoro@38 676 DIGITAL_INIT_DONE:
andrewm@282 677 // Check if we should use an external multiplexer capelet
andrewm@282 678 // The valid values are 0 (off), 1 (2 ch), 2 (4 ch), 3 (8 ch)
andrewm@282 679 // This can only happen on PRU1 because of how the pins are mapped
andrewm@282 680 LBBO r2, reg_comm_addr, COMM_PRU_NUMBER, 4
andrewm@282 681 QBNE MUX_INIT_DONE, r2, 1
andrewm@282 682 LBBO r2, reg_comm_addr, COMM_MUX_CONFIG, 4
andrewm@282 683 AND r2, r2, 0x03
andrewm@282 684 QBEQ MUX_INIT_DONE, r2, 0
andrewm@282 685 // If we get here, we are using the mux. Prepare flags and initial state.
andrewm@282 686 LSL r2, r2, FLAG_BIT_MUX_CONFIG0
andrewm@282 687 OR reg_flags, reg_flags, r2
andrewm@282 688 // Clear lower 6 bits of r30 which controls the mux pins
andrewm@282 689 MOV r2, 0xFFFFFFC0
andrewm@282 690 AND reg_pru1_mux_pins, reg_pru1_mux_pins, r2
andrewm@282 691 MUX_INIT_DONE:
andrewm@282 692
giuliomoro@102 693 // Find out whether we should use SPI ADC and DAC
giuliomoro@102 694 LBBO r2, reg_comm_addr, COMM_USE_SPI, 4
giuliomoro@102 695 QBEQ SPI_FLAG_CHECK_DONE, r2, 0
giuliomoro@102 696 SET reg_flags, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 697 SPI_FLAG_CHECK_DONE:
giuliomoro@102 698 // If we don't use SPI, then skip all this init
giuliomoro@102 699 QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@12 700
giuliomoro@102 701 // Load the number of channels: valid values are 8, 4 or 2
giuliomoro@102 702 LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4
giuliomoro@102 703 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ?
giuliomoro@102 704 LDI reg_num_channels, 8 // If N >= 8, N = 8
giuliomoro@102 705 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 706 SPI_NUM_CHANNELS_LT8:
giuliomoro@102 707 QBGT SPI_NUM_CHANNELS_LT4, reg_num_channels, 4 // 4 > num_channels ?
giuliomoro@102 708 LDI reg_num_channels, 4 // If N >= 4, N = 4
giuliomoro@102 709 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 710 SPI_NUM_CHANNELS_LT4:
giuliomoro@102 711 LDI reg_num_channels, 2 // else N = 2
andrewm@12 712 SPI_NUM_CHANNELS_DONE:
andrewm@0 713
giuliomoro@102 714 // Init SPI clock
giuliomoro@102 715 MOV r2, 0x02
giuliomoro@102 716 MOV r3, CLOCK_BASE + CLOCK_SPI0
giuliomoro@102 717 SBBO r2, r3, 0, 4
andrewm@0 718
giuliomoro@102 719 // Reset SPI and wait for finish
giuliomoro@102 720 MOV r2, 0x02
giuliomoro@102 721 SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4
andrewm@0 722
andrewm@0 723 SPI_WAIT_RESET:
giuliomoro@102 724 LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4
giuliomoro@102 725 QBBC SPI_WAIT_RESET, r2, 0
andrewm@0 726
giuliomoro@102 727 // Turn off SPI channels
giuliomoro@102 728 MOV r2, 0
giuliomoro@102 729 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
giuliomoro@102 730 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 731
giuliomoro@102 732 // Set to master; chip select lines enabled (CS0 used for DAC)
giuliomoro@102 733 MOV r2, 0x00
giuliomoro@102 734 SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4
andrewm@0 735
giuliomoro@102 736 // Configure CH0 for DAC
giuliomoro@102 737 MOV r2, (3 << 27) | (DAC_DPE << 16) | (DAC_TRM << 12) | ((DAC_WL - 1) << 7) | (DAC_CLK_DIV << 2) | DAC_CLK_MODE | (1 << 6)
giuliomoro@102 738 SBBO r2, reg_spi_addr, SPI_CH0CONF, 4
andrewm@0 739
giuliomoro@102 740 // Configure CH1 for ADC
giuliomoro@102 741 MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE
giuliomoro@102 742 SBBO r2, reg_spi_addr, SPI_CH1CONF, 4
andrewm@0 743
giuliomoro@102 744 // Turn on SPI channels
giuliomoro@102 745 MOV r2, 0x01
giuliomoro@102 746 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
giuliomoro@102 747 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 748
giuliomoro@102 749 // DAC power-on reset sequence
giuliomoro@102 750 MOV r2, (0x07 << AD5668_COMMAND_OFFSET)
giuliomoro@102 751 DAC_WRITE r2
andrewm@0 752
giuliomoro@102 753 // Initialise ADC
giuliomoro@102 754 MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET)
giuliomoro@102 755 ADC_WRITE r2, r2
andrewm@0 756
giuliomoro@102 757 // Enable DAC internal reference
giuliomoro@102 758 MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET)
giuliomoro@102 759 DAC_WRITE r2
andrewm@0 760
giuliomoro@102 761 // Read ADC ch0 and ch1: result is always 2 samples behind so start here
giuliomoro@102 762 MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET)
giuliomoro@102 763 ADC_WRITE r2, r2
andrewm@0 764
giuliomoro@102 765 MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET)
giuliomoro@102 766 ADC_WRITE r2, r2
andrewm@0 767 SPI_INIT_DONE:
andrewm@0 768
giuliomoro@102 769 // Prepare McASP0 for audio
giuliomoro@102 770 MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP
giuliomoro@102 771 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off
giuliomoro@102 772 MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0
giuliomoro@102 773 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0
giuliomoro@102 774 MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0
giuliomoro@102 775 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0
giuliomoro@102 776 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0
andrewm@0 777
giuliomoro@102 778 MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on
giuliomoro@102 779 MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP
giuliomoro@102 780 MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction
giuliomoro@102 781 MCASP_REG_WRITE MCASP_DLBCTL, 0x00
giuliomoro@102 782 MCASP_REG_WRITE MCASP_DITCTL, 0x00
giuliomoro@102 783 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive
giuliomoro@102 784 MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format
giuliomoro@102 785 MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode
giuliomoro@102 786 MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge
giuliomoro@102 787 MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant?
giuliomoro@102 788 MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1
giuliomoro@102 789 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts
giuliomoro@102 790 MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit
giuliomoro@102 791 MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format
giuliomoro@102 792 MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode
giuliomoro@102 793 MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv
giuliomoro@102 794 MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX
giuliomoro@102 795 MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1
giuliomoro@102 796 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts
andrewm@0 797
giuliomoro@102 798 MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser
giuliomoro@102 799 MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser
giuliomoro@102 800 MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs
giuliomoro@102 801 MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00
andrewm@0 802
giuliomoro@102 803 MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors
giuliomoro@102 804 MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors
andrewm@0 805
giuliomoro@102 806 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST
giuliomoro@102 807 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST
andrewm@0 808
andrewm@0 809 // The above write sequence will have temporarily changed the AHCLKX frequency
andrewm@0 810 // The PLL needs time to settle or the sample rate will be unstable and possibly
andrewm@0 811 // cause an underrun. Give it ~1ms before going on.
andrewm@0 812 // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed
andrewm@0 813
giuliomoro@102 814 MOV r2, 1 << 28
giuliomoro@102 815 MOV r3, GPIO1 + GPIO_SETDATAOUT
giuliomoro@102 816 SBBO r2, r3, 0, 4
andrewm@0 817
andrewm@0 818 MOV r2, 100000
andrewm@0 819 MCASP_INIT_WAIT:
giuliomoro@102 820 SUB r2, r2, 1
giuliomoro@102 821 QBNE MCASP_INIT_WAIT, r2, 0
andrewm@0 822
giuliomoro@102 823 MOV r2, 1 << 28
giuliomoro@102 824 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
giuliomoro@102 825 SBBO r2, r3, 0, 4
giuliomoro@102 826
andrewm@0 827 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST
andrewm@0 828 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST
andrewm@0 829 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR
andrewm@0 830 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR
andrewm@0 831 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST
andrewm@0 832 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST
andrewm@0 833
andrewm@0 834 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow
andrewm@0 835
andrewm@0 836 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST
andrewm@0 837 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST
andrewm@0 838
andrewm@0 839 // Initialisation
giuliomoro@38 840 LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP)
giuliomoro@38 841 MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer
giuliomoro@38 842 LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize
giuliomoro@38 843 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels
giuliomoro@38 844 LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above
giuliomoro@38 845 MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer
giuliomoro@38 846 LSL reg_mcasp_buf1, reg_frame_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize
giuliomoro@38 847 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on
giuliomoro@38 848 MOV r2, 0
giuliomoro@38 849 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0
giuliomoro@38 850 /* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started.
giuliomoro@38 851 Will leave it here for future reference
giuliomoro@38 852 //Initialise all SPI and audio buffers (DAC0, DAC1, ADC0, ADC1) to zero.
giuliomoro@38 853 //This is useful for analog outs so they do not have spikes during the first buffer.
giuliomoro@38 854 //This is not very useful for audio, as you still hear the initial "tumpf" when the converter starts
giuliomoro@38 855 //and each sample in the DAC buffer is reset to 0 after it is written to the DAC.
giuliomoro@38 856
giuliomoro@38 857 QBBC SPI_INIT_BUFFER_DONE, reg_flags, FLAG_BIT_USE_SPI
giuliomoro@38 858 //Initialize SPI buffers
giuliomoro@38 859 //compute the memory offset of the end of the audio buffer and store it in r4
giuliomoro@38 860 SUB r4, reg_dac_buf1, reg_dac_buf0 // length of the buffer, assumes reg_dac_buf1>ref_dac_buf0
giuliomoro@38 861 LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1)
giuliomoro@38 862 ADD r4, reg_dac_buf0, r4 //total offset
giuliomoro@38 863 MOV r2, 0// value to store
giuliomoro@38 864 MOV r3, 0 // offset counter
giuliomoro@38 865 SPI_INIT_BUFFER_LOOP:
giuliomoro@38 866 SBCO r2, C_ADC_DAC_MEM, r3, 4
giuliomoro@38 867 ADD r3, r3, 4
giuliomoro@38 868 QBGT SPI_INIT_BUFFER_LOOP, r3, r4
giuliomoro@38 869 SPI_INIT_BUFFER_DONE:
giuliomoro@38 870
giuliomoro@38 871 //Initialize audio buffers
giuliomoro@38 872 //compute the memory offset of the end of the audio buffer and store it in r4
giuliomoro@38 873 SUB r4, reg_mcasp_buf1, reg_mcasp_buf0 // length of the buffer, assumes reg_mcasp_buf1>ref_mcasp_buf0
giuliomoro@38 874 LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1)
giuliomoro@38 875 ADD r4, reg_mcasp_buf0, r4 //total offset
giuliomoro@38 876 MOV r2, 0 // value to store
giuliomoro@38 877 MOV r3, 0 // offset counter
giuliomoro@38 878 MCASP_INIT_BUFFER_LOOP:
giuliomoro@38 879 SBCO r2, C_MCASP_MEM, r3, 4
giuliomoro@38 880 ADD r3, r3, 4
giuliomoro@38 881 QBGT MCASP_INIT_BUFFER_LOOP, r3, r4
giuliomoro@38 882 */
andrewm@0 883 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied
andrewm@0 884 // the first output slot. Send one more word before jumping into the loop.
andrewm@0 885 MCASP_DAC_WAIT_BEFORE_LOOP:
giuliomoro@102 886 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
giuliomoro@102 887 QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 888
giuliomoro@102 889 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00
andrewm@0 890
andrewm@0 891 // Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC
andrewm@0 892 // in sync in terms of which TDM slot we are reading (empirically found that we should throw this away
andrewm@0 893 // rather than keep it and invert the phase)
andrewm@0 894 MCASP_ADC_WAIT_BEFORE_LOOP:
giuliomoro@102 895 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
giuliomoro@102 896 QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 897
giuliomoro@102 898 MCASP_REG_READ_EXT MCASP_RBUF, r2
andrewm@0 899
andrewm@0 900 WRITE_ONE_BUFFER:
giuliomoro@38 901
giuliomoro@102 902 // Write a single buffer of DAC samples and read a buffer of ADC samples
giuliomoro@102 903 // Load starting positions
giuliomoro@102 904 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer
giuliomoro@102 905 LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels
giuliomoro@102 906 LSL reg_adc_current, reg_frame_total, r2
giuliomoro@102 907 LSL reg_adc_current, reg_adc_current, 2 // N * 2 * 2 * bufsize
giuliomoro@102 908 ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC
giuliomoro@102 909 MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
giuliomoro@102 910 LSL reg_mcasp_adc_current, reg_frame_total, r2 // McASP ADC: starts (N/2)*2*2*bufsize beyond DAC
giuliomoro@102 911 LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1
giuliomoro@102 912 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current
giuliomoro@102 913 MOV reg_frame_current, 0
giuliomoro@102 914 QBBS DIGITAL_BASE_CHECK_SET, reg_flags, FLAG_BIT_BUFFER1 //check which buffer we are using for DIGITAL
giuliomoro@16 915 // if we are here, we are using buffer0
giuliomoro@102 916 MOV reg_digital_current, MEM_DIGITAL_BASE
giuliomoro@102 917 QBA DIGITAL_BASE_CHECK_DONE
giuliomoro@19 918 DIGITAL_BASE_CHECK_SET: //if we are here, we are using buffer1
giuliomoro@102 919 MOV reg_digital_current, MEM_DIGITAL_BASE+MEM_DIGITAL_BUFFER1_OFFSET //so adjust offset appropriately
giuliomoro@19 920 DIGITAL_BASE_CHECK_DONE:
giuliomoro@16 921
andrewm@0 922 WRITE_LOOP:
giuliomoro@102 923 // Write N channels to DAC from successive values in memory
giuliomoro@102 924 // At the same time, read N channels from ADC
giuliomoro@102 925 // Unrolled by a factor of 2 to get high and low words
giuliomoro@102 926 MOV r1, 0
andrewm@0 927 ADC_DAC_LOOP:
giuliomoro@102 928 QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI
giuliomoro@102 929 // Load next 2 SPI DAC samples and store zero in their place
giuliomoro@102 930 LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4
giuliomoro@102 931 MOV r2, 0
giuliomoro@102 932 SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4
giuliomoro@102 933 ADD reg_dac_current, reg_dac_current, 4
andrewm@0 934 SPI_DAC_LOAD_DONE:
andrewm@0 935
giuliomoro@102 936 // On even iterations, load two more samples and choose the first one
giuliomoro@102 937 // On odd iterations, transmit the second of the samples already loaded
giuliomoro@102 938 // QBBS MCASP_DAC_HIGH_WORD, r1, 1
giuliomoro@102 939 QBBS MCASP_DAC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 940 MCASP_DAC_LOW_WORD:
giuliomoro@102 941 // Load next 2 Audio DAC samples and store zero in their place
giuliomoro@102 942 LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
giuliomoro@102 943 MOV r2, 0
giuliomoro@102 944 SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4
giuliomoro@102 945 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4
andrewm@0 946
giuliomoro@102 947 // Mask out the low word (first in little endian)
giuliomoro@102 948 MOV r2, 0xFFFF
giuliomoro@102 949 AND r7, reg_mcasp_dac_data, r2
andrewm@0 950
giuliomoro@102 951 QBA MCASP_WAIT_XSTAT
andrewm@0 952 MCASP_DAC_HIGH_WORD:
giuliomoro@102 953 // Take the high word of the previously loaded data
giuliomoro@102 954 LSR r7, reg_mcasp_dac_data, 16
andrewm@0 955
giuliomoro@102 956 // Every 2 channels we send one audio sample; this loop already
giuliomoro@102 957 // sends exactly two SPI channels.
giuliomoro@102 958 // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
andrewm@0 959 MCASP_WAIT_XSTAT:
giuliomoro@102 960 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
giuliomoro@102 961 QBBS START, r2, MCASP_XSTAT_XUNDRN_BIT // if underrun occurred, reset the PRU
giuliomoro@102 962 QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 963
giuliomoro@102 964 MCASP_REG_WRITE_EXT MCASP_XBUF, r7
andrewm@0 965
giuliomoro@102 966 // Same idea with ADC: even iterations, load the sample into the low word, odd
giuliomoro@102 967 // iterations, load the sample into the high word and store
giuliomoro@102 968 // QBBS MCASP_ADC_HIGH_WORD, r1, 1
giuliomoro@102 969 QBBS MCASP_ADC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 970 MCASP_ADC_LOW_WORD:
giuliomoro@102 971 // Start ADC data at 0
giuliomoro@102 972 LDI reg_mcasp_adc_data, 0
andrewm@0 973
giuliomoro@102 974 // Now wait for a received word to become available from the audio ADC
andrewm@0 975 MCASP_WAIT_RSTAT_LOW:
giuliomoro@102 976 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
giuliomoro@102 977 QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 978
giuliomoro@102 979 // Mask low word and store in ADC data register
giuliomoro@102 980 MCASP_REG_READ_EXT MCASP_RBUF, r3
giuliomoro@102 981 MOV r2, 0xFFFF
giuliomoro@102 982 AND reg_mcasp_adc_data, r3, r2
giuliomoro@102 983 QBA MCASP_ADC_DONE
andrewm@0 984
andrewm@0 985 MCASP_ADC_HIGH_WORD:
giuliomoro@102 986 // Wait for a received word to become available from the audio ADC
andrewm@0 987 MCASP_WAIT_RSTAT_HIGH:
giuliomoro@102 988 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
giuliomoro@102 989 QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 990
giuliomoro@102 991 // Read data and shift 16 bits to the left (into the high word)
giuliomoro@102 992 MCASP_REG_READ_EXT MCASP_RBUF, r3
giuliomoro@102 993 LSL r3, r3, 16
giuliomoro@102 994 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3
andrewm@0 995
giuliomoro@102 996 // Now store the result and increment the pointer
giuliomoro@102 997 SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4
giuliomoro@102 998 ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4
andrewm@0 999 MCASP_ADC_DONE:
giuliomoro@102 1000 QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI
giuliomoro@26 1001
giuliomoro@102 1002 // DAC: transmit low word (first in little endian)
giuliomoro@102 1003 MOV r2, 0xFFFF
giuliomoro@102 1004 AND r7, reg_dac_data, r2
giuliomoro@102 1005 LSL r7, r7, AD5668_DATA_OFFSET
giuliomoro@102 1006 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
giuliomoro@102 1007 OR r7, r7, r8
andrewm@346 1008 DAC_CHANNEL_REORDER r8, r1
andrewm@346 1009 LSL r8, r8, AD5668_ADDRESS_OFFSET
giuliomoro@102 1010 OR r7, r7, r8
giuliomoro@102 1011 DAC_WRITE r7
andrewm@0 1012
giuliomoro@102 1013 // Read ADC channels: result is always 2 commands behind
giuliomoro@102 1014 // Start by reading channel 2 (result is channel 0) and go
giuliomoro@102 1015 // to N+2, but masking the channel number to be between 0 and N-1
giuliomoro@102 1016 LDI reg_adc_data, 0
giuliomoro@102 1017 ADD r8, r1, 2
giuliomoro@102 1018 SUB r7, reg_num_channels, 1
giuliomoro@102 1019 AND r8, r8, r7
giuliomoro@102 1020 LSL r8, r8, AD7699_CHANNEL_OFFSET
giuliomoro@102 1021 MOV r7, AD7699_CFG_MASK
giuliomoro@102 1022 OR r7, r7, r8
giuliomoro@38 1023
giuliomoro@102 1024 ADC_WRITE_GPIO r7, r7, r1
andrewm@0 1025
giuliomoro@102 1026 // Mask out only the relevant 16 bits and store in reg_adc_data
giuliomoro@102 1027 MOV r2, 0xFFFF
giuliomoro@102 1028 AND reg_adc_data, r7, r2
giuliomoro@102 1029 // Increment channel index
giuliomoro@102 1030 ADD r1, r1, 1
andrewm@0 1031
giuliomoro@102 1032 // DAC: transmit high word (second in little endian)
giuliomoro@102 1033 LSR r7, reg_dac_data, 16
giuliomoro@102 1034 LSL r7, r7, AD5668_DATA_OFFSET
giuliomoro@102 1035 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
giuliomoro@102 1036 OR r7, r7, r8
andrewm@346 1037 DAC_CHANNEL_REORDER r8, r1
andrewm@346 1038 LSL r8, r8, AD5668_ADDRESS_OFFSET
giuliomoro@102 1039 OR r7, r7, r8
giuliomoro@102 1040 DAC_WRITE r7
andrewm@0 1041
giuliomoro@102 1042 // Read ADC channels: result is always 2 commands behind
giuliomoro@102 1043 // Start by reading channel 2 (result is channel 0) and go
giuliomoro@102 1044 // to N+2, but masking the channel number to be between 0 and N-1
giuliomoro@102 1045 ADD r8, r1, 2
giuliomoro@102 1046 SUB r7, reg_num_channels, 1
giuliomoro@102 1047 AND r8, r8, r7
giuliomoro@102 1048 LSL r8, r8, AD7699_CHANNEL_OFFSET
giuliomoro@102 1049 MOV r7, AD7699_CFG_MASK
giuliomoro@102 1050 OR r7, r7, r8
giuliomoro@102 1051 ADC_WRITE r7, r7
andrewm@0 1052
giuliomoro@102 1053 // Move this result up to the 16 high bits
giuliomoro@102 1054 LSL r7, r7, 16
giuliomoro@102 1055 OR reg_adc_data, reg_adc_data, r7
andrewm@0 1056
giuliomoro@102 1057 // Store 2 ADC words in memory
giuliomoro@102 1058 SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
giuliomoro@102 1059 ADD reg_adc_current, reg_adc_current, 4
andrewm@0 1060
andrewm@282 1061 // If enabled, update the multiplexer settings
andrewm@282 1062 QBNE MUX_0_3_DONE, r1, 3 // Change mux settings for ch0-3 after reading ch. 3
andrewm@282 1063 MUX_INCREMENT_0_TO_3
andrewm@282 1064 MUX_0_3_DONE:
andrewm@283 1065 QBNE MUX_4_7_DONE, r1, 7 // Change mux settings for ch4-7 after reading ch. 7
andrewm@283 1066 MUX_INCREMENT_4_TO_7
andrewm@283 1067 MUX_4_7_DONE:
andrewm@282 1068
giuliomoro@102 1069 // Toggle the high/low word for McASP control (since we send one word out of
giuliomoro@102 1070 // 32 bits for each pair of SPI channels)
giuliomoro@102 1071 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
giuliomoro@102 1072
giuliomoro@102 1073 // Repeat 4 times for 8 channels (2 samples per loop, r1 += 1 already happened)
giuliomoro@102 1074 // For 4 or 2 channels, repeat 2 or 1 times, according to flags
giuliomoro@102 1075 ADD r1, r1, 1
giuliomoro@102 1076 QBNE ADC_DAC_LOOP, r1, reg_num_channels
giuliomoro@102 1077 QBA ADC_DAC_LOOP_DONE
giuliomoro@102 1078 SPI_SKIP_WRITE:
giuliomoro@102 1079 // We get here only if the SPI ADC and DAC are disabled
giuliomoro@102 1080 // Just keep the loop going for McASP
andrewm@0 1081
giuliomoro@102 1082 // Toggle the high/low word for McASP control (since we send one word out of
giuliomoro@102 1083 // 32 bits for each pair of SPI channels)
giuliomoro@102 1084 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
andrewm@12 1085
giuliomoro@102 1086 ADD r1, r1, 2
giuliomoro@102 1087 QBNE ADC_DAC_LOOP, r1, reg_num_channels
andrewm@0 1088
andrewm@282 1089 ADC_DAC_LOOP_DONE:
giuliomoro@102 1090 // Increment number of frames, see if we have more to write
giuliomoro@102 1091 ADD reg_frame_current, reg_frame_current, 1
giuliomoro@102 1092 QBNE WRITE_LOOP, reg_frame_current, reg_frame_total
andrewm@0 1093
andrewm@0 1094 WRITE_LOOP_DONE:
giuliomoro@102 1095 // Now done, swap the buffers and do the next one
giuliomoro@102 1096 // Use r2 as a temp register
giuliomoro@102 1097 MOV r2, reg_dac_buf0
giuliomoro@102 1098 MOV reg_dac_buf0, reg_dac_buf1
giuliomoro@102 1099 MOV reg_dac_buf1, r2
giuliomoro@102 1100 MOV r2, reg_mcasp_buf0
giuliomoro@102 1101 MOV reg_mcasp_buf0, reg_mcasp_buf1
giuliomoro@102 1102 MOV reg_mcasp_buf1, r2
giuliomoro@102 1103 XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1) //flip the buffer flag
andrewm@0 1104
andrewm@346 1105 // If multiplexer capelet is enabled, save which channel we got to
andrewm@346 1106 // Muxes 0-3 change at a different time than muxes 4-7 but the first
andrewm@346 1107 // of these is sufficient to capture where we are
andrewm@346 1108 MOV r2, FLAG_MASK_MUX_CONFIG
andrewm@346 1109 AND r2, reg_flags, r2
andrewm@346 1110 QBEQ MUX_CHANNEL_SAVE_DONE, r2, 0
andrewm@346 1111 AND r2, reg_pru1_mux_pins, 0x03
andrewm@346 1112 SBBO r2, reg_comm_addr, COMM_MUX_END_CHANNEL, 4
andrewm@346 1113 MUX_CHANNEL_SAVE_DONE:
andrewm@346 1114
giuliomoro@102 1115 // Notify ARM of buffer swap
giuliomoro@102 1116 AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit
giuliomoro@102 1117 SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4
giuliomoro@102 1118 MOV R31.b0, PRU1_ARM_INTERRUPT + 16 // Interrupt to host loop
andrewm@45 1119
giuliomoro@102 1120 // Increment the frame count in the comm buffer (for status monitoring)
giuliomoro@102 1121 LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
giuliomoro@102 1122 ADD r2, r2, reg_frame_total
giuliomoro@102 1123 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
andrewm@0 1124
giuliomoro@102 1125 // If LED blink enabled, toggle every 4096 frames
giuliomoro@102 1126 LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4
giuliomoro@102 1127 QBEQ LED_BLINK_DONE, r3, 0
giuliomoro@102 1128 MOV r1, 0x1000
giuliomoro@102 1129 AND r2, r2, r1 // Test (frame count & 4096)
giuliomoro@102 1130 QBEQ LED_BLINK_OFF, r2, 0
giuliomoro@102 1131 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
giuliomoro@102 1132 MOV r1, GPIO_SETDATAOUT
giuliomoro@102 1133 ADD r3, r3, r1 // Address for GPIO set register
giuliomoro@102 1134 SBBO r2, r3, 0, 4 // Set GPIO pin
giuliomoro@102 1135 QBA LED_BLINK_DONE
andrewm@0 1136 LED_BLINK_OFF:
giuliomoro@102 1137 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
giuliomoro@102 1138 MOV r1, GPIO_CLEARDATAOUT
giuliomoro@102 1139 ADD r3, r3, r1 // Address for GPIO clear register
giuliomoro@102 1140 SBBO r2, r3, 0, 4 // Clear GPIO pin
andrewm@0 1141 LED_BLINK_DONE:
giuliomoro@102 1142 // Check if we should finish: flag is zero as long as it should run
giuliomoro@102 1143 LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4
giuliomoro@102 1144 QBEQ WRITE_ONE_BUFFER, r2, 0
andrewm@0 1145
andrewm@0 1146 CLEANUP:
giuliomoro@102 1147 MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP
andrewm@0 1148
giuliomoro@102 1149 // Turn off SPI if enabled
giuliomoro@102 1150 QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 1151
giuliomoro@102 1152 MOV r3, SPI_BASE + SPI_CH0CONF
giuliomoro@102 1153 LBBO r2, r3, 0, 4
giuliomoro@102 1154 CLR r2, r2, 13
giuliomoro@102 1155 CLR r2, r2, 27
giuliomoro@102 1156 SBBO r2, r3, 0, 4
andrewm@0 1157
giuliomoro@102 1158 MOV r3, SPI_BASE + SPI_CH0CTRL
giuliomoro@102 1159 LBBO r2, r3, 0, 4
giuliomoro@102 1160 CLR r2, r2, 1
giuliomoro@102 1161 SBBO r2, r3, 0, 4
andrewm@0 1162 SPI_CLEANUP_DONE:
giuliomoro@102 1163 // Signal the ARM that we have finished
giuliomoro@102 1164 MOV R31.b0, PRU0_ARM_INTERRUPT + 16
giuliomoro@102 1165 HALT