annotate pru_rtaudio.p @ 39:638bc1ae2500 staging

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