annotate pru_rtaudio.p @ 269:ac8eb07afcf5

Oxygen text added to each render.cpp file for the default projects. Text includes project explanation from Wiki, edited in places. Empty project added as a default project. Doxyfile updated. Each of the project locations added to INPUT configuration option. Consider just watching the whole project file so all new projects are automatically pulled through.
author Robert Jack <robert.h.jack@gmail.com>
date Tue, 17 May 2016 15:40:16 +0100
parents c706be7daad7
children 33e0e4831763
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@188 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@188 483 QBLT CASE_4_OR_8_CHANNELS, reg_num_channels, 2
giuliomoro@188 484 CASE_2_CHANNELS:
giuliomoro@188 485 AND r27, reg_frame_current, 0x1
giuliomoro@188 486 QBNE GPIO_DONE, r27, 0
giuliomoro@188 487 JMP DO_GPIO
giuliomoro@188 488 CASE_4_OR_8_CHANNELS:
giuliomoro@102 489 AND r27, do_gpio, 0x3 // only do a DIGITAL every 2 SPI I/O
giuliomoro@102 490 QBNE GPIO_DONE, r27, 0
giuliomoro@188 491 DO_GPIO:
giuliomoro@16 492 //from here to GPIO_DONE takes 1.8us, while usually ADC_WAIT_FOR_FINISH only waits for 1.14us.
giuliomoro@19 493 //TODO: it would be better to split the DIGITAL stuff in two parts:
giuliomoro@16 494 //- one taking place during DAC_WRITE which sets the GPIO_OE
giuliomoro@16 495 //- and the other during ADC_WRITE which actually reads DATAIN and writes CLEAR/SET DATAOUT
giuliomoro@39 496 //r27 is actually r27, so do not use r27 from here to ...
giuliomoro@102 497 LBBO r27, reg_digital_current, 0, 4
giuliomoro@102 498 JAL r28.w0, DIGITAL // note that this is not called as a macro, but with JAL. r28 will contain the return address
giuliomoro@102 499 SBBO r27, reg_digital_current, 0, 4
giuliomoro@16 500 //..here you can start using r27 again
giuliomoro@102 501 ADD reg_digital_current, reg_digital_current, 4 //increment pointer
giuliomoro@16 502 GPIO_DONE:
giuliomoro@102 503 ADC_WAIT_FOR_FINISH
giuliomoro@102 504 ADC_RX out
giuliomoro@102 505 ADC_CS_UNASSERT
giuliomoro@16 506 .endm
giuliomoro@16 507
andrewm@0 508 // Write a McASP register
andrewm@0 509 .macro MCASP_REG_WRITE
andrewm@0 510 .mparam reg, value
giuliomoro@102 511 MOV r27, value
giuliomoro@102 512 SBBO r27, reg_mcasp_addr, reg, 4
andrewm@0 513 .endm
andrewm@0 514
andrewm@0 515 // Write a McASP register beyond the 0xFF boundary
andrewm@0 516 .macro MCASP_REG_WRITE_EXT
andrewm@0 517 .mparam reg, value
giuliomoro@102 518 MOV r27, value
giuliomoro@102 519 MOV r28, reg
giuliomoro@102 520 ADD r28, reg_mcasp_addr, r28
giuliomoro@102 521 SBBO r27, r28, 0, 4
andrewm@0 522 .endm
andrewm@0 523
andrewm@0 524 // Read a McASP register
andrewm@0 525 .macro MCASP_REG_READ
andrewm@0 526 .mparam reg, value
giuliomoro@102 527 LBBO value, reg_mcasp_addr, reg, 4
andrewm@0 528 .endm
andrewm@0 529
andrewm@0 530 // Read a McASP register beyond the 0xFF boundary
andrewm@0 531 .macro MCASP_REG_READ_EXT
andrewm@0 532 .mparam reg, value
giuliomoro@102 533 MOV r28, reg
giuliomoro@102 534 ADD r28, reg_mcasp_addr, r28
giuliomoro@102 535 LBBO value, r28, 0, 4
andrewm@0 536 .endm
andrewm@0 537
andrewm@0 538 // Set a bit and wait for it to come up
andrewm@0 539 .macro MCASP_REG_SET_BIT_AND_POLL
andrewm@0 540 .mparam reg, mask
giuliomoro@102 541 MOV r27, mask
giuliomoro@102 542 LBBO r28, reg_mcasp_addr, reg, 4
giuliomoro@102 543 OR r28, r28, r27
giuliomoro@102 544 SBBO r28, reg_mcasp_addr, reg, 4
andrewm@0 545 POLL:
giuliomoro@102 546 LBBO r28, reg_mcasp_addr, reg, 4
giuliomoro@102 547 AND r28, r28, r27
giuliomoro@102 548 QBEQ POLL, r28, 0
andrewm@0 549 .endm
andrewm@0 550
andrewm@0 551 START:
giuliomoro@102 552 // Set up c24 and c25 offsets with CTBIR register
giuliomoro@102 553 // Thus C24 points to start of PRU0 RAM
giuliomoro@102 554 MOV r3, 0x22020 // CTBIR0
giuliomoro@102 555 MOV r2, 0
giuliomoro@102 556 SBBO r2, r3, 0, 4
andrewm@0 557
giuliomoro@102 558 // Set up c28 pointer offset for shared PRU RAM
giuliomoro@102 559 MOV r3, 0x22028 // CTPPR0
giuliomoro@102 560 MOV r2, 0x00000120 // To get address 0x00012000
giuliomoro@102 561 SBBO r2, r3, 0, 4
andrewm@0 562
giuliomoro@102 563 // Load useful registers for addressing SPI
giuliomoro@102 564 MOV reg_comm_addr, SHARED_COMM_MEM_BASE
giuliomoro@102 565 MOV reg_spi_addr, SPI_BASE
giuliomoro@102 566 MOV reg_mcasp_addr, MCASP_BASE
andrewm@0 567
giuliomoro@102 568 // Set ARM such that PRU can write to registers
giuliomoro@102 569 LBCO r0, C4, 4, 4
giuliomoro@102 570 CLR r0, r0, 4
giuliomoro@102 571 SBCO r0, C4, 4, 4
andrewm@0 572
giuliomoro@102 573 // Clear flags
giuliomoro@102 574 MOV reg_flags, 0
giuliomoro@102 575 // Default number of channels in case SPI disabled
giuliomoro@102 576 LDI reg_num_channels, 8
andrewm@0 577
giuliomoro@102 578 // Find out whether we should use DIGITAL
giuliomoro@102 579 LBBO r2, reg_comm_addr, COMM_USE_DIGITAL, 4
giuliomoro@102 580 QBEQ DIGITAL_INIT_DONE, r2, 0 // if we use digital
giuliomoro@102 581 SET reg_flags, reg_flags, FLAG_BIT_USE_DIGITAL
giuliomoro@38 582 /* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started.
giuliomoro@38 583 Will leave it here for future reference
giuliomoro@38 584 DIGITAL_INIT: //set the digital buffer to 0x0000ffff (all inputs), to prevent unwanted high outputs
giuliomoro@38 585 //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 586 MOV r2, 0x0000ffff //value to store. 0x0000ffff means all inputs
giuliomoro@102 587 MOV r3, MEM_DIGITAL_BASE //start of the digital buffer
giuliomoro@102 588 MOV r4, MEM_DIGITAL_BASE+2*MEM_DIGITAL_BUFFER1_OFFSET //end of the digital buffer
giuliomoro@38 589 DIGITAL_INIT_BUFFER_LOOP:
giuliomoro@102 590 SBBO r2, r3, 0, 4
giuliomoro@102 591 ADD r3, r3, 4 //increment pointer
giuliomoro@102 592 QBGT DIGITAL_INIT_BUFFER_LOOP, r3, r4 //loop until we reach the end of the buffer
giuliomoro@38 593 */
giuliomoro@38 594 DIGITAL_INIT_DONE:
giuliomoro@102 595 // Find out whether we should use SPI ADC and DAC
giuliomoro@102 596 LBBO r2, reg_comm_addr, COMM_USE_SPI, 4
giuliomoro@102 597 QBEQ SPI_FLAG_CHECK_DONE, r2, 0
giuliomoro@102 598 SET reg_flags, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 599 SPI_FLAG_CHECK_DONE:
giuliomoro@102 600 // If we don't use SPI, then skip all this init
giuliomoro@102 601 QBBC SPI_INIT_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@12 602
giuliomoro@102 603 // Load the number of channels: valid values are 8, 4 or 2
giuliomoro@102 604 LBBO reg_num_channels, reg_comm_addr, COMM_NUM_CHANNELS, 4
giuliomoro@102 605 QBGT SPI_NUM_CHANNELS_LT8, reg_num_channels, 8 // 8 > num_channels ?
giuliomoro@102 606 LDI reg_num_channels, 8 // If N >= 8, N = 8
giuliomoro@102 607 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 608 SPI_NUM_CHANNELS_LT8:
giuliomoro@102 609 QBGT SPI_NUM_CHANNELS_LT4, reg_num_channels, 4 // 4 > num_channels ?
giuliomoro@102 610 LDI reg_num_channels, 4 // If N >= 4, N = 4
giuliomoro@102 611 QBA SPI_NUM_CHANNELS_DONE
andrewm@12 612 SPI_NUM_CHANNELS_LT4:
giuliomoro@102 613 LDI reg_num_channels, 2 // else N = 2
andrewm@12 614 SPI_NUM_CHANNELS_DONE:
andrewm@0 615
giuliomoro@102 616 // Init SPI clock
giuliomoro@102 617 MOV r2, 0x02
giuliomoro@102 618 MOV r3, CLOCK_BASE + CLOCK_SPI0
giuliomoro@102 619 SBBO r2, r3, 0, 4
andrewm@0 620
giuliomoro@102 621 // Reset SPI and wait for finish
giuliomoro@102 622 MOV r2, 0x02
giuliomoro@102 623 SBBO r2, reg_spi_addr, SPI_SYSCONFIG, 4
andrewm@0 624
andrewm@0 625 SPI_WAIT_RESET:
giuliomoro@102 626 LBBO r2, reg_spi_addr, SPI_SYSSTATUS, 4
giuliomoro@102 627 QBBC SPI_WAIT_RESET, r2, 0
andrewm@0 628
giuliomoro@102 629 // Turn off SPI channels
giuliomoro@102 630 MOV r2, 0
giuliomoro@102 631 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
giuliomoro@102 632 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 633
giuliomoro@102 634 // Set to master; chip select lines enabled (CS0 used for DAC)
giuliomoro@102 635 MOV r2, 0x00
giuliomoro@102 636 SBBO r2, reg_spi_addr, SPI_MODULCTRL, 4
andrewm@0 637
giuliomoro@102 638 // Configure CH0 for DAC
giuliomoro@102 639 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 640 SBBO r2, reg_spi_addr, SPI_CH0CONF, 4
andrewm@0 641
giuliomoro@102 642 // Configure CH1 for ADC
giuliomoro@102 643 MOV r2, (3 << 27) | (ADC_DPE << 16) | (ADC_TRM << 12) | ((ADC_WL - 1) << 7) | (ADC_CLK_DIV << 2) | ADC_CLK_MODE
giuliomoro@102 644 SBBO r2, reg_spi_addr, SPI_CH1CONF, 4
andrewm@0 645
giuliomoro@102 646 // Turn on SPI channels
giuliomoro@102 647 MOV r2, 0x01
giuliomoro@102 648 SBBO r2, reg_spi_addr, SPI_CH0CTRL, 4
giuliomoro@102 649 SBBO r2, reg_spi_addr, SPI_CH1CTRL, 4
andrewm@0 650
giuliomoro@102 651 // DAC power-on reset sequence
giuliomoro@102 652 MOV r2, (0x07 << AD5668_COMMAND_OFFSET)
giuliomoro@102 653 DAC_WRITE r2
andrewm@0 654
giuliomoro@102 655 // Initialise ADC
giuliomoro@102 656 MOV r2, AD7699_CFG_MASK | (0 << AD7699_CHANNEL_OFFSET) | (0 << AD7699_SEQ_OFFSET)
giuliomoro@102 657 ADC_WRITE r2, r2
andrewm@0 658
giuliomoro@102 659 // Enable DAC internal reference
giuliomoro@102 660 MOV r2, (0x08 << AD5668_COMMAND_OFFSET) | (0x01 << AD5668_REF_OFFSET)
giuliomoro@102 661 DAC_WRITE r2
andrewm@0 662
giuliomoro@102 663 // Read ADC ch0 and ch1: result is always 2 samples behind so start here
giuliomoro@102 664 MOV r2, AD7699_CFG_MASK | (0x00 << AD7699_CHANNEL_OFFSET)
giuliomoro@102 665 ADC_WRITE r2, r2
andrewm@0 666
giuliomoro@102 667 MOV r2, AD7699_CFG_MASK | (0x01 << AD7699_CHANNEL_OFFSET)
giuliomoro@102 668 ADC_WRITE r2, r2
andrewm@0 669 SPI_INIT_DONE:
andrewm@0 670
giuliomoro@102 671 // Prepare McASP0 for audio
giuliomoro@102 672 MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP
giuliomoro@102 673 MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off
giuliomoro@102 674 MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0
giuliomoro@102 675 MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0
giuliomoro@102 676 MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0
giuliomoro@102 677 MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0
giuliomoro@102 678 MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0
andrewm@0 679
giuliomoro@102 680 MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on
giuliomoro@102 681 MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP
giuliomoro@102 682 MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction
giuliomoro@102 683 MCASP_REG_WRITE MCASP_DLBCTL, 0x00
giuliomoro@102 684 MCASP_REG_WRITE MCASP_DITCTL, 0x00
giuliomoro@102 685 MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive
giuliomoro@102 686 MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format
giuliomoro@102 687 MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode
giuliomoro@102 688 MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge
giuliomoro@102 689 MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant?
giuliomoro@102 690 MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1
giuliomoro@102 691 MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts
giuliomoro@102 692 MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit
giuliomoro@102 693 MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format
giuliomoro@102 694 MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode
giuliomoro@102 695 MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv
giuliomoro@102 696 MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX
giuliomoro@102 697 MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1
giuliomoro@102 698 MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts
andrewm@0 699
giuliomoro@102 700 MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser
giuliomoro@102 701 MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser
giuliomoro@102 702 MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs
giuliomoro@102 703 MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00
andrewm@0 704
giuliomoro@102 705 MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors
giuliomoro@102 706 MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors
andrewm@0 707
giuliomoro@102 708 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST
giuliomoro@102 709 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST
andrewm@0 710
andrewm@0 711 // The above write sequence will have temporarily changed the AHCLKX frequency
andrewm@0 712 // The PLL needs time to settle or the sample rate will be unstable and possibly
andrewm@0 713 // cause an underrun. Give it ~1ms before going on.
andrewm@0 714 // 10ns per loop iteration = 10^-8s --> 10^5 iterations needed
andrewm@0 715
giuliomoro@102 716 MOV r2, 1 << 28
giuliomoro@102 717 MOV r3, GPIO1 + GPIO_SETDATAOUT
giuliomoro@102 718 SBBO r2, r3, 0, 4
andrewm@0 719
andrewm@0 720 MOV r2, 100000
andrewm@0 721 MCASP_INIT_WAIT:
giuliomoro@102 722 SUB r2, r2, 1
giuliomoro@102 723 QBNE MCASP_INIT_WAIT, r2, 0
andrewm@0 724
giuliomoro@102 725 MOV r2, 1 << 28
giuliomoro@102 726 MOV r3, GPIO1 + GPIO_CLEARDATAOUT
giuliomoro@102 727 SBBO r2, r3, 0, 4
giuliomoro@102 728
andrewm@0 729 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST
andrewm@0 730 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST
andrewm@0 731 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR
andrewm@0 732 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR
andrewm@0 733 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST
andrewm@0 734 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST
andrewm@0 735
andrewm@0 736 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow
andrewm@0 737
andrewm@0 738 MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST
andrewm@0 739 MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST
andrewm@0 740
andrewm@0 741 // Initialisation
giuliomoro@38 742 LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP)
giuliomoro@38 743 MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer
giuliomoro@38 744 LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize
giuliomoro@38 745 LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels
giuliomoro@38 746 LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above
giuliomoro@38 747 MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer
giuliomoro@38 748 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 749 CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on
giuliomoro@38 750 MOV r2, 0
giuliomoro@38 751 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0
giuliomoro@38 752 /* This block of code is not really needed, as the memory is initialized by ARM before the PRU is started.
giuliomoro@38 753 Will leave it here for future reference
giuliomoro@38 754 //Initialise all SPI and audio buffers (DAC0, DAC1, ADC0, ADC1) to zero.
giuliomoro@38 755 //This is useful for analog outs so they do not have spikes during the first buffer.
giuliomoro@38 756 //This is not very useful for audio, as you still hear the initial "tumpf" when the converter starts
giuliomoro@38 757 //and each sample in the DAC buffer is reset to 0 after it is written to the DAC.
giuliomoro@38 758
giuliomoro@38 759 QBBC SPI_INIT_BUFFER_DONE, reg_flags, FLAG_BIT_USE_SPI
giuliomoro@38 760 //Initialize SPI buffers
giuliomoro@38 761 //compute the memory offset of the end of the audio buffer and store it in r4
giuliomoro@38 762 SUB r4, reg_dac_buf1, reg_dac_buf0 // length of the buffer, assumes reg_dac_buf1>ref_dac_buf0
giuliomoro@38 763 LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1)
giuliomoro@38 764 ADD r4, reg_dac_buf0, r4 //total offset
giuliomoro@38 765 MOV r2, 0// value to store
giuliomoro@38 766 MOV r3, 0 // offset counter
giuliomoro@38 767 SPI_INIT_BUFFER_LOOP:
giuliomoro@38 768 SBCO r2, C_ADC_DAC_MEM, r3, 4
giuliomoro@38 769 ADD r3, r3, 4
giuliomoro@38 770 QBGT SPI_INIT_BUFFER_LOOP, r3, r4
giuliomoro@38 771 SPI_INIT_BUFFER_DONE:
giuliomoro@38 772
giuliomoro@38 773 //Initialize audio buffers
giuliomoro@38 774 //compute the memory offset of the end of the audio buffer and store it in r4
giuliomoro@38 775 SUB r4, reg_mcasp_buf1, reg_mcasp_buf0 // length of the buffer, assumes reg_mcasp_buf1>ref_mcasp_buf0
giuliomoro@38 776 LSL r4, r4, 2 //length of four buffers (DAC0, DAC1, ADC0, ADC1)
giuliomoro@38 777 ADD r4, reg_mcasp_buf0, r4 //total offset
giuliomoro@38 778 MOV r2, 0 // value to store
giuliomoro@38 779 MOV r3, 0 // offset counter
giuliomoro@38 780 MCASP_INIT_BUFFER_LOOP:
giuliomoro@38 781 SBCO r2, C_MCASP_MEM, r3, 4
giuliomoro@38 782 ADD r3, r3, 4
giuliomoro@38 783 QBGT MCASP_INIT_BUFFER_LOOP, r3, r4
giuliomoro@38 784 */
andrewm@0 785 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied
andrewm@0 786 // the first output slot. Send one more word before jumping into the loop.
andrewm@0 787 MCASP_DAC_WAIT_BEFORE_LOOP:
giuliomoro@102 788 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
giuliomoro@102 789 QBBC MCASP_DAC_WAIT_BEFORE_LOOP, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 790
giuliomoro@102 791 MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00
andrewm@0 792
andrewm@0 793 // Likewise, read and discard the first sample we get back from the ADC. This keeps the DAC and ADC
andrewm@0 794 // in sync in terms of which TDM slot we are reading (empirically found that we should throw this away
andrewm@0 795 // rather than keep it and invert the phase)
andrewm@0 796 MCASP_ADC_WAIT_BEFORE_LOOP:
giuliomoro@102 797 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
giuliomoro@102 798 QBBC MCASP_ADC_WAIT_BEFORE_LOOP, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 799
giuliomoro@102 800 MCASP_REG_READ_EXT MCASP_RBUF, r2
andrewm@0 801
andrewm@0 802 WRITE_ONE_BUFFER:
giuliomoro@38 803
giuliomoro@102 804 // Write a single buffer of DAC samples and read a buffer of ADC samples
giuliomoro@102 805 // Load starting positions
giuliomoro@102 806 MOV reg_dac_current, reg_dac_buf0 // DAC: reg_dac_current is current pointer
giuliomoro@102 807 LMBD r2, reg_num_channels, 1 // 1, 2 or 3 for 2, 4 or 8 channels
giuliomoro@102 808 LSL reg_adc_current, reg_frame_total, r2
giuliomoro@102 809 LSL reg_adc_current, reg_adc_current, 2 // N * 2 * 2 * bufsize
giuliomoro@102 810 ADD reg_adc_current, reg_adc_current, reg_dac_current // ADC: starts N * 2 * 2 * bufsize beyond DAC
giuliomoro@102 811 MOV reg_mcasp_dac_current, reg_mcasp_buf0 // McASP: set current DAC pointer
giuliomoro@102 812 LSL reg_mcasp_adc_current, reg_frame_total, r2 // McASP ADC: starts (N/2)*2*2*bufsize beyond DAC
giuliomoro@102 813 LSL reg_mcasp_adc_current, reg_mcasp_adc_current, 1
giuliomoro@102 814 ADC reg_mcasp_adc_current, reg_mcasp_adc_current, reg_mcasp_dac_current
giuliomoro@102 815 MOV reg_frame_current, 0
giuliomoro@102 816 QBBS DIGITAL_BASE_CHECK_SET, reg_flags, FLAG_BIT_BUFFER1 //check which buffer we are using for DIGITAL
giuliomoro@16 817 // if we are here, we are using buffer0
giuliomoro@102 818 MOV reg_digital_current, MEM_DIGITAL_BASE
giuliomoro@102 819 QBA DIGITAL_BASE_CHECK_DONE
giuliomoro@19 820 DIGITAL_BASE_CHECK_SET: //if we are here, we are using buffer1
giuliomoro@102 821 MOV reg_digital_current, MEM_DIGITAL_BASE+MEM_DIGITAL_BUFFER1_OFFSET //so adjust offset appropriately
giuliomoro@19 822 DIGITAL_BASE_CHECK_DONE:
giuliomoro@16 823
andrewm@0 824 WRITE_LOOP:
giuliomoro@102 825 // Write N channels to DAC from successive values in memory
giuliomoro@102 826 // At the same time, read N channels from ADC
giuliomoro@102 827 // Unrolled by a factor of 2 to get high and low words
giuliomoro@102 828 MOV r1, 0
andrewm@0 829 ADC_DAC_LOOP:
giuliomoro@102 830 QBBC SPI_DAC_LOAD_DONE, reg_flags, FLAG_BIT_USE_SPI
giuliomoro@102 831 // Load next 2 SPI DAC samples and store zero in their place
giuliomoro@102 832 LBCO reg_dac_data, C_ADC_DAC_MEM, reg_dac_current, 4
giuliomoro@102 833 MOV r2, 0
giuliomoro@102 834 SBCO r2, C_ADC_DAC_MEM, reg_dac_current, 4
giuliomoro@102 835 ADD reg_dac_current, reg_dac_current, 4
andrewm@0 836 SPI_DAC_LOAD_DONE:
andrewm@0 837
giuliomoro@102 838 // On even iterations, load two more samples and choose the first one
giuliomoro@102 839 // On odd iterations, transmit the second of the samples already loaded
giuliomoro@102 840 // QBBS MCASP_DAC_HIGH_WORD, r1, 1
giuliomoro@102 841 QBBS MCASP_DAC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 842 MCASP_DAC_LOW_WORD:
giuliomoro@102 843 // Load next 2 Audio DAC samples and store zero in their place
giuliomoro@102 844 LBCO reg_mcasp_dac_data, C_MCASP_MEM, reg_mcasp_dac_current, 4
giuliomoro@102 845 MOV r2, 0
giuliomoro@102 846 SBCO r2, C_MCASP_MEM, reg_mcasp_dac_current, 4
giuliomoro@102 847 ADD reg_mcasp_dac_current, reg_mcasp_dac_current, 4
andrewm@0 848
giuliomoro@102 849 // Mask out the low word (first in little endian)
giuliomoro@102 850 MOV r2, 0xFFFF
giuliomoro@102 851 AND r7, reg_mcasp_dac_data, r2
andrewm@0 852
giuliomoro@102 853 QBA MCASP_WAIT_XSTAT
andrewm@0 854 MCASP_DAC_HIGH_WORD:
giuliomoro@102 855 // Take the high word of the previously loaded data
giuliomoro@102 856 LSR r7, reg_mcasp_dac_data, 16
andrewm@0 857
giuliomoro@102 858 // Every 2 channels we send one audio sample; this loop already
giuliomoro@102 859 // sends exactly two SPI channels.
giuliomoro@102 860 // Wait for McASP XSTAT[XDATA] to set indicating we can write more data
andrewm@0 861 MCASP_WAIT_XSTAT:
giuliomoro@102 862 LBBO r2, reg_mcasp_addr, MCASP_XSTAT, 4
giuliomoro@102 863 QBBS START, r2, MCASP_XSTAT_XUNDRN_BIT // if underrun occurred, reset the PRU
giuliomoro@102 864 QBBC MCASP_WAIT_XSTAT, r2, MCASP_XSTAT_XDATA_BIT
andrewm@0 865
giuliomoro@102 866 MCASP_REG_WRITE_EXT MCASP_XBUF, r7
andrewm@0 867
giuliomoro@102 868 // Same idea with ADC: even iterations, load the sample into the low word, odd
giuliomoro@102 869 // iterations, load the sample into the high word and store
giuliomoro@102 870 // QBBS MCASP_ADC_HIGH_WORD, r1, 1
giuliomoro@102 871 QBBS MCASP_ADC_HIGH_WORD, reg_flags, FLAG_BIT_MCASP_HWORD
andrewm@0 872 MCASP_ADC_LOW_WORD:
giuliomoro@102 873 // Start ADC data at 0
giuliomoro@102 874 LDI reg_mcasp_adc_data, 0
andrewm@0 875
giuliomoro@102 876 // Now wait for a received word to become available from the audio ADC
andrewm@0 877 MCASP_WAIT_RSTAT_LOW:
giuliomoro@102 878 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
giuliomoro@102 879 QBBC MCASP_WAIT_RSTAT_LOW, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 880
giuliomoro@102 881 // Mask low word and store in ADC data register
giuliomoro@102 882 MCASP_REG_READ_EXT MCASP_RBUF, r3
giuliomoro@102 883 MOV r2, 0xFFFF
giuliomoro@102 884 AND reg_mcasp_adc_data, r3, r2
giuliomoro@102 885 QBA MCASP_ADC_DONE
andrewm@0 886
andrewm@0 887 MCASP_ADC_HIGH_WORD:
giuliomoro@102 888 // Wait for a received word to become available from the audio ADC
andrewm@0 889 MCASP_WAIT_RSTAT_HIGH:
giuliomoro@102 890 LBBO r2, reg_mcasp_addr, MCASP_RSTAT, 4
giuliomoro@102 891 QBBC MCASP_WAIT_RSTAT_HIGH, r2, MCASP_RSTAT_RDATA_BIT
andrewm@0 892
giuliomoro@102 893 // Read data and shift 16 bits to the left (into the high word)
giuliomoro@102 894 MCASP_REG_READ_EXT MCASP_RBUF, r3
giuliomoro@102 895 LSL r3, r3, 16
giuliomoro@102 896 OR reg_mcasp_adc_data, reg_mcasp_adc_data, r3
andrewm@0 897
giuliomoro@102 898 // Now store the result and increment the pointer
giuliomoro@102 899 SBCO reg_mcasp_adc_data, C_MCASP_MEM, reg_mcasp_adc_current, 4
giuliomoro@102 900 ADD reg_mcasp_adc_current, reg_mcasp_adc_current, 4
andrewm@0 901 MCASP_ADC_DONE:
giuliomoro@102 902 QBBC SPI_SKIP_WRITE, reg_flags, FLAG_BIT_USE_SPI
giuliomoro@26 903
giuliomoro@102 904 // DAC: transmit low word (first in little endian)
giuliomoro@102 905 MOV r2, 0xFFFF
giuliomoro@102 906 AND r7, reg_dac_data, r2
giuliomoro@102 907 LSL r7, r7, AD5668_DATA_OFFSET
giuliomoro@102 908 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
giuliomoro@102 909 OR r7, r7, r8
giuliomoro@102 910 LSL r8, r1, AD5668_ADDRESS_OFFSET
giuliomoro@102 911 OR r7, r7, r8
giuliomoro@102 912 DAC_WRITE r7
andrewm@0 913
giuliomoro@102 914 // Read ADC channels: result is always 2 commands behind
giuliomoro@102 915 // Start by reading channel 2 (result is channel 0) and go
giuliomoro@102 916 // to N+2, but masking the channel number to be between 0 and N-1
giuliomoro@102 917 LDI reg_adc_data, 0
giuliomoro@102 918 ADD r8, r1, 2
giuliomoro@102 919 SUB r7, reg_num_channels, 1
giuliomoro@102 920 AND r8, r8, r7
giuliomoro@102 921 LSL r8, r8, AD7699_CHANNEL_OFFSET
giuliomoro@102 922 MOV r7, AD7699_CFG_MASK
giuliomoro@102 923 OR r7, r7, r8
giuliomoro@38 924
giuliomoro@102 925 ADC_WRITE_GPIO r7, r7, r1
andrewm@0 926
giuliomoro@102 927 // Mask out only the relevant 16 bits and store in reg_adc_data
giuliomoro@102 928 MOV r2, 0xFFFF
giuliomoro@102 929 AND reg_adc_data, r7, r2
giuliomoro@102 930 // Increment channel index
giuliomoro@102 931 ADD r1, r1, 1
andrewm@0 932
giuliomoro@102 933 // DAC: transmit high word (second in little endian)
giuliomoro@102 934 LSR r7, reg_dac_data, 16
giuliomoro@102 935 LSL r7, r7, AD5668_DATA_OFFSET
giuliomoro@102 936 MOV r8, (0x03 << AD5668_COMMAND_OFFSET)
giuliomoro@102 937 OR r7, r7, r8
giuliomoro@102 938 LSL r8, r1, AD5668_ADDRESS_OFFSET
giuliomoro@102 939 OR r7, r7, r8
giuliomoro@102 940 DAC_WRITE r7
andrewm@0 941
giuliomoro@102 942 // Read ADC channels: result is always 2 commands behind
giuliomoro@102 943 // Start by reading channel 2 (result is channel 0) and go
giuliomoro@102 944 // to N+2, but masking the channel number to be between 0 and N-1
giuliomoro@102 945 ADD r8, r1, 2
giuliomoro@102 946 SUB r7, reg_num_channels, 1
giuliomoro@102 947 AND r8, r8, r7
giuliomoro@102 948 LSL r8, r8, AD7699_CHANNEL_OFFSET
giuliomoro@102 949 MOV r7, AD7699_CFG_MASK
giuliomoro@102 950 OR r7, r7, r8
giuliomoro@102 951 ADC_WRITE r7, r7
andrewm@0 952
giuliomoro@102 953 // Move this result up to the 16 high bits
giuliomoro@102 954 LSL r7, r7, 16
giuliomoro@102 955 OR reg_adc_data, reg_adc_data, r7
andrewm@0 956
giuliomoro@102 957 // Store 2 ADC words in memory
giuliomoro@102 958 SBCO reg_adc_data, C_ADC_DAC_MEM, reg_adc_current, 4
giuliomoro@102 959 ADD reg_adc_current, reg_adc_current, 4
andrewm@0 960
giuliomoro@102 961 // Toggle the high/low word for McASP control (since we send one word out of
giuliomoro@102 962 // 32 bits for each pair of SPI channels)
giuliomoro@102 963 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
giuliomoro@102 964
giuliomoro@102 965 // Repeat 4 times for 8 channels (2 samples per loop, r1 += 1 already happened)
giuliomoro@102 966 // For 4 or 2 channels, repeat 2 or 1 times, according to flags
giuliomoro@102 967 ADD r1, r1, 1
giuliomoro@102 968 QBNE ADC_DAC_LOOP, r1, reg_num_channels
giuliomoro@102 969 QBA ADC_DAC_LOOP_DONE
giuliomoro@102 970 SPI_SKIP_WRITE:
giuliomoro@102 971 // We get here only if the SPI ADC and DAC are disabled
giuliomoro@102 972 // Just keep the loop going for McASP
andrewm@0 973
giuliomoro@102 974 // Toggle the high/low word for McASP control (since we send one word out of
giuliomoro@102 975 // 32 bits for each pair of SPI channels)
giuliomoro@102 976 XOR reg_flags, reg_flags, (1 << FLAG_BIT_MCASP_HWORD)
andrewm@12 977
giuliomoro@102 978 ADD r1, r1, 2
giuliomoro@102 979 QBNE ADC_DAC_LOOP, r1, reg_num_channels
andrewm@0 980
andrewm@0 981 ADC_DAC_LOOP_DONE:
giuliomoro@102 982 // Increment number of frames, see if we have more to write
giuliomoro@102 983 ADD reg_frame_current, reg_frame_current, 1
giuliomoro@102 984 QBNE WRITE_LOOP, reg_frame_current, reg_frame_total
andrewm@0 985
andrewm@0 986 WRITE_LOOP_DONE:
giuliomoro@102 987 // Now done, swap the buffers and do the next one
giuliomoro@102 988 // Use r2 as a temp register
giuliomoro@102 989 MOV r2, reg_dac_buf0
giuliomoro@102 990 MOV reg_dac_buf0, reg_dac_buf1
giuliomoro@102 991 MOV reg_dac_buf1, r2
giuliomoro@102 992 MOV r2, reg_mcasp_buf0
giuliomoro@102 993 MOV reg_mcasp_buf0, reg_mcasp_buf1
giuliomoro@102 994 MOV reg_mcasp_buf1, r2
giuliomoro@102 995 XOR reg_flags, reg_flags, (1 << FLAG_BIT_BUFFER1) //flip the buffer flag
andrewm@0 996
giuliomoro@102 997 // Notify ARM of buffer swap
giuliomoro@102 998 AND r2, reg_flags, (1 << FLAG_BIT_BUFFER1) // Mask out every but low bit
giuliomoro@102 999 SBBO r2, reg_comm_addr, COMM_CURRENT_BUFFER, 4
giuliomoro@102 1000 MOV R31.b0, PRU1_ARM_INTERRUPT + 16 // Interrupt to host loop
andrewm@45 1001
giuliomoro@102 1002 // Increment the frame count in the comm buffer (for status monitoring)
giuliomoro@102 1003 LBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
giuliomoro@102 1004 ADD r2, r2, reg_frame_total
giuliomoro@102 1005 SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4
andrewm@0 1006
giuliomoro@102 1007 // If LED blink enabled, toggle every 4096 frames
giuliomoro@102 1008 LBBO r3, reg_comm_addr, COMM_LED_ADDRESS, 4
giuliomoro@102 1009 QBEQ LED_BLINK_DONE, r3, 0
giuliomoro@102 1010 MOV r1, 0x1000
giuliomoro@102 1011 AND r2, r2, r1 // Test (frame count & 4096)
giuliomoro@102 1012 QBEQ LED_BLINK_OFF, r2, 0
giuliomoro@102 1013 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
giuliomoro@102 1014 MOV r1, GPIO_SETDATAOUT
giuliomoro@102 1015 ADD r3, r3, r1 // Address for GPIO set register
giuliomoro@102 1016 SBBO r2, r3, 0, 4 // Set GPIO pin
giuliomoro@102 1017 QBA LED_BLINK_DONE
andrewm@0 1018 LED_BLINK_OFF:
giuliomoro@102 1019 LBBO r2, reg_comm_addr, COMM_LED_PIN_MASK, 4
giuliomoro@102 1020 MOV r1, GPIO_CLEARDATAOUT
giuliomoro@102 1021 ADD r3, r3, r1 // Address for GPIO clear register
giuliomoro@102 1022 SBBO r2, r3, 0, 4 // Clear GPIO pin
andrewm@0 1023 LED_BLINK_DONE:
giuliomoro@102 1024 // Check if we should finish: flag is zero as long as it should run
giuliomoro@102 1025 LBBO r2, reg_comm_addr, COMM_SHOULD_STOP, 4
giuliomoro@102 1026 QBEQ WRITE_ONE_BUFFER, r2, 0
andrewm@0 1027
andrewm@0 1028 CLEANUP:
giuliomoro@102 1029 MCASP_REG_WRITE MCASP_GBLCTL, 0x00 // Turn off McASP
andrewm@0 1030
giuliomoro@102 1031 // Turn off SPI if enabled
giuliomoro@102 1032 QBBC SPI_CLEANUP_DONE, reg_flags, FLAG_BIT_USE_SPI
andrewm@0 1033
giuliomoro@102 1034 MOV r3, SPI_BASE + SPI_CH0CONF
giuliomoro@102 1035 LBBO r2, r3, 0, 4
giuliomoro@102 1036 CLR r2, r2, 13
giuliomoro@102 1037 CLR r2, r2, 27
giuliomoro@102 1038 SBBO r2, r3, 0, 4
andrewm@0 1039
giuliomoro@102 1040 MOV r3, SPI_BASE + SPI_CH0CTRL
giuliomoro@102 1041 LBBO r2, r3, 0, 4
giuliomoro@102 1042 CLR r2, r2, 1
giuliomoro@102 1043 SBBO r2, r3, 0, 4
andrewm@0 1044 SPI_CLEANUP_DONE:
giuliomoro@102 1045 // Signal the ARM that we have finished
giuliomoro@102 1046 MOV R31.b0, PRU0_ARM_INTERRUPT + 16
giuliomoro@102 1047 HALT