annotate pru_rtaudio.p @ 151:e9c9404e3d1f ClockSync

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