annotate pru_rtaudio.p @ 45:579c86316008 newapi

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