annotate pru_rtaudio.p @ 26:6d64ee8c0754 matrix_gpio

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