Mercurial > hg > beaglert
changeset 21:0d80ff9e2227
Add float<->int macros to PRU code (still to integrate); formatting cleanups
author | andrewm |
---|---|
date | Sun, 08 Feb 2015 00:20:01 +0000 |
parents | 901d205d1a3c |
children | 472e892c6e41 |
files | pru_rtaudio.p |
diffstat | 1 files changed, 230 insertions(+), 55 deletions(-) [+] |
line wrap: on
line diff
--- a/pru_rtaudio.p Sat Feb 07 16:41:56 2015 +0000 +++ b/pru_rtaudio.p Sun Feb 08 00:20:01 2015 +0000 @@ -205,6 +205,181 @@ // r27, r28 used in macros #define reg_mcasp_addr r29 // Base address for McASP +// Convert float to 16-bit int, multiplying by 32768 +// Converts -1.0 to 1.0 to a full 16-bit range +// input and output can safely be the same register +.macro FLOAT_TO_INT16 +.mparam input, output + // int exponent = ((input >> 23) & 0xFF) + LSR r27, input, 23 // exponent goes in r27 + AND r27, r27, 0xFF + + // Actual exponent is 127 less than the above; below -15 we + // should return 0. So check if it is less than 112. + QBLE EXPONENT_GREQ_MINUS15, r27, 112 + LDI output, 0 + QBA FLOAT_TO_INT16_DONE +EXPONENT_GREQ_MINUS15: + + // Next check if exponent is greater than or equal to 0 (i.e. + // 127 in our adjusted version. If so we return the max. + QBGT EXPONENT_LT_ZERO, r27, 127 + QBBS NEGATIVE_MAX, input, 31 // Is sign negative? + LDI output, 32767 // Max positive value + QBA FLOAT_TO_INT16_DONE +NEGATIVE_MAX: + LDI output, 32768 // Actually will be -32768 in signed + QBA FLOAT_TO_INT16_DONE +EXPONENT_LT_ZERO: + + // Mask out the mantissa and shift + // int mantissa = (input & 0x7FFFFF) | (1 << 23) + MOV r28, 0x007FFFFF + AND r28, r28, input + SET r28, 23 + + // Shift right by -(exponent - 127 - 8) to produce an int + // after effectively multiplying by 2^15 + // ---> (135 - exponent) + RSB r27, r27, 135 + LSR r28, r28, r27 + + // Finally, check the sign bit and invert if needed + QBBS NEGATIVE_RESULT, input, 31 + // Positive result: but might be 32768 so needs checking + LDI r27, 0x7FFF + MIN output, r27, r28 + QBA FLOAT_TO_INT16_DONE +NEGATIVE_RESULT: + // Take negative: invert the bits and add 1 + LDI r27, 0xFFFF + XOR r28, r28, r27 + ADD r28, r28, 1 + CLR output, r28, 16 // Clear carry bit if present +FLOAT_TO_INT16_DONE: +.endm + + +// Convert float to 16-bit unsigned int, multiplying by 65536 +// Converts 0.0 to 1.0 to a full 16-bit range +// input and output can safely be the same register +.macro FLOAT_TO_UINT16 +.mparam input, output + QBBC NONNEGATIVE, input, 31 // Is sign negative? + LDI output, 0 // All < 0 inputs produce 0 output + QBA FLOAT_TO_UINT16_DONE +NONNEGATIVE: + // int exponent = ((input >> 23) & 0xFF) + LSR r27, input, 23 // exponent goes in r27 + AND r27, r27, 0xFF + + // Actual exponent is 127 less than the above; below -16 we + // should return 0. So check if it is less than 111. + QBLE EXPONENT_GREQ_MINUS16, r27, 111 + LDI output, 0 + QBA FLOAT_TO_UINT16_DONE +EXPONENT_GREQ_MINUS16: + + // Next check if exponent is greater than or equal to 0 (i.e. + // 127 in our adjusted version. If so we return the max. + QBGT EXPONENT_LT_ZERO, r27, 127 + LDI output, 65535 // Max positive value + QBA FLOAT_TO_UINT16_DONE +EXPONENT_LT_ZERO: + + // Mask out the mantissa and shift + // int mantissa = (input & 0x7FFFFF) | (1 << 23) + MOV r28, 0x007FFFFF + AND r28, r28, input + SET r28, 23 + + // Shift right by -(exponent - 127 - 7) to produce an int + // after effectively multiplying by 2^16 + // ---> (134 - exponent) + RSB r27, r27, 134 + LSR r28, r28, r27 + + // Check for 65536 and clip at 65535 + LDI r27, 0xFFFF + MIN output, r27, r28 +FLOAT_TO_UINT16_DONE: +.endm + + +// Convert a 16-bit int to float. This macro assumes that the upper +// 16 bits of input are 0 and may behave strangely if this is not the case. +// input and output must be different registers +.macro INT16_TO_FLOAT +.mparam input, output + // Check edge cases first: 0 and -32768 (= 32768 in unsigned) + QBNE INPUT_NOT_ZERO, input, 0 + LDI output, 0 + QBA INT16_TO_FLOAT_DONE +INPUT_NOT_ZERO: + LDI r28, 32768 + QBNE INPUT_NOT_MIN, input, r28 + MOV output, 0xBF800000 // -1.0 + QBA INT16_TO_FLOAT_DONE +INPUT_NOT_MIN: + // Check for negative values = values with bit 15 set + MOV output, input + QBBC NEGATIVE_DONE, output, 15 + LDI r28, 0xFFFF + XOR output, output, r28 + ADD output, output, 1 + CLR output, 16 // Clear any carry bit +NEGATIVE_DONE: + // Now we need to find the highest bit that is 1 in order to determine + // the exponent + LMBD r28, output, 1 + + // Calculate exponent field: 127 + 8 + (r28 - 23) = 112 + r28 + ADD r27, r28, 112 + + // Take 23 minus the result to get the shift + RSB r28, r28, 23 + LSL output, output, r28 + + // Now clear bit 23 (implicitly 1) and replace it with the exponent + CLR output, output, 23 + LSL r27, r27, 23 + OR output, output, r27 + + // Put the sign bit back in place + QBBC INT16_TO_FLOAT_DONE, input, 15 + SET output, 31 +INT16_TO_FLOAT_DONE: +.endm + +// Convert a 16-bit unsigned int to float. +.macro UINT16_TO_FLOAT +.mparam input, output + MOV output, input + + // Clear upper 16 bits + LDI r27, 0xFFFF + AND output, output, r27 + + // If zero, we're done + QBEQ UINT16_TO_FLOAT_DONE, output, 0 + + // Now we need to find the highest bit that is 1 in order to determine + // the exponent + LMBD r28, output, 1 + + // Calculate exponent field: 127 + 7 + (r28 - 23) = 111 + r28 + ADD r27, r28, 111 + + // Take 23 minus the result to get the shift + RSB r28, r28, 23 + LSL output, output, r28 + + // Now clear bit 23 (implicitly 1) and replace it with the exponent + CLR output, output, 23 + LSL r27, r27, 23 + OR output, output, r27 +UINT16_TO_FLOAT_DONE: +.endm // Bring CS line low to write to DAC .macro DAC_CS_ASSERT @@ -439,45 +614,45 @@ ADC_WRITE r2, r2 SPI_INIT_DONE: -// Prepare McASP0 for audio -MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP -MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off -MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0 -MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0 -MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0 -MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0 -MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0 + // Prepare McASP0 for audio + MCASP_REG_WRITE MCASP_GBLCTL, 0 // Disable McASP + MCASP_REG_WRITE_EXT MCASP_SRCTL0, 0 // All serialisers off + MCASP_REG_WRITE_EXT MCASP_SRCTL1, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL2, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL3, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL4, 0 + MCASP_REG_WRITE_EXT MCASP_SRCTL5, 0 -MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on -MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP -MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction -MCASP_REG_WRITE MCASP_DLBCTL, 0x00 -MCASP_REG_WRITE MCASP_DITCTL, 0x00 -MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive -MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format -MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode -MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge -MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? -MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1 -MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts -MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit -MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format -MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode -MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv -MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX -MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1 -MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts + MCASP_REG_WRITE MCASP_PWRIDLESYSCONFIG, 0x02 // Power on + MCASP_REG_WRITE MCASP_PFUNC, 0x00 // All pins are McASP + MCASP_REG_WRITE MCASP_PDIR, MCASP_OUTPUT_PINS // Set pin direction + MCASP_REG_WRITE MCASP_DLBCTL, 0x00 + MCASP_REG_WRITE MCASP_DITCTL, 0x00 + MCASP_REG_WRITE MCASP_RMASK, MCASP_DATA_MASK // 16 bit data receive + MCASP_REG_WRITE MCASP_RFMT, MCASP_DATA_FORMAT // Set data format + MCASP_REG_WRITE MCASP_AFSRCTL, 0x100 // I2S mode + MCASP_REG_WRITE MCASP_ACLKRCTL, 0x80 // Sample on rising edge + MCASP_REG_WRITE MCASP_AHCLKRCTL, 0x8001 // Internal clock, not inv, /2; irrelevant? + MCASP_REG_WRITE MCASP_RTDM, 0x03 // Enable TDM slots 0 and 1 + MCASP_REG_WRITE MCASP_RINTCTL, 0x00 // No interrupts + MCASP_REG_WRITE MCASP_XMASK, MCASP_DATA_MASK // 16 bit data transmit + MCASP_REG_WRITE MCASP_XFMT, MCASP_DATA_FORMAT // Set data format + MCASP_REG_WRITE MCASP_AFSXCTL, 0x100 // I2S mode + MCASP_REG_WRITE MCASP_ACLKXCTL, 0x00 // Transmit on rising edge, sync. xmit and recv + MCASP_REG_WRITE MCASP_AHCLKXCTL, 0x8001 // External clock from AHCLKX + MCASP_REG_WRITE MCASP_XTDM, 0x03 // Enable TDM slots 0 and 1 + MCASP_REG_WRITE MCASP_XINTCTL, 0x00 // No interrupts -MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser -MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser -MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs -MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00 + MCASP_REG_WRITE_EXT MCASP_SRCTL_R, 0x02 // Set up receive serialiser + MCASP_REG_WRITE_EXT MCASP_SRCTL_X, 0x01 // Set up transmit serialiser + MCASP_REG_WRITE_EXT MCASP_WFIFOCTL, 0x00 // Disable FIFOs + MCASP_REG_WRITE_EXT MCASP_RFIFOCTL, 0x00 -MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors -MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors + MCASP_REG_WRITE MCASP_XSTAT, 0xFF // Clear transmit errors + MCASP_REG_WRITE MCASP_RSTAT, 0xFF // Clear receive errors -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST + MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 1) // Set RHCLKRST + MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 9) // Set XHCLKRST // The above write sequence will have temporarily changed the AHCLKX frequency // The PLL needs time to settle or the sample rate will be unstable and possibly @@ -488,7 +663,7 @@ MOV r3, GPIO1 + GPIO_SETDATAOUT SBBO r2, r3, 0, 4 -MOV r2, 100000 + MOV r2, 100000 MCASP_INIT_WAIT: SUB r2, r2, 1 QBNE MCASP_INIT_WAIT, r2, 0 @@ -497,29 +672,29 @@ MOV r3, GPIO1 + GPIO_CLEARDATAOUT SBBO r2, r3, 0, 4 -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST + MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 0) // Set RCLKRST + MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 8) // Set XCLKRST + MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 2) // Set RSRCLR + MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 10) // Set XSRCLR + MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 3) // Set RSMRST + MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 11) // Set XSMRST -MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow + MCASP_REG_WRITE_EXT MCASP_XBUF, 0x00 // Write to the transmit buffer to prevent underflow -MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST -MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST + MCASP_REG_SET_BIT_AND_POLL MCASP_RGBLCTL, (1 << 4) // Set RFRST + MCASP_REG_SET_BIT_AND_POLL MCASP_XGBLCTL, (1 << 12) // Set XFRST // Initialisation -LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP) -MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer -LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize -LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels -LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above -MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer -LSL reg_mcasp_buf1, reg_frame_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize -CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on -MOV r2, 0 -SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 + LBBO reg_frame_total, reg_comm_addr, COMM_BUFFER_FRAMES, 4 // Total frame count (SPI; 0.5x-2x for McASP) + MOV reg_dac_buf0, 0 // DAC buffer 0 start pointer + LSL reg_dac_buf1, reg_frame_total, 1 // DAC buffer 1 start pointer = N[ch]*2[bytes]*bufsize + LMBD r2, reg_num_channels, 1 // Returns 1, 2 or 3 depending on the number of channels + LSL reg_dac_buf1, reg_dac_buf1, r2 // Multiply by 2, 4 or 8 to get the N[ch] scaling above + MOV reg_mcasp_buf0, 0 // McASP DAC buffer 0 start pointer + LSL reg_mcasp_buf1, reg_frame_total, r2 // McASP DAC buffer 1 start pointer = 2[ch]*2[bytes]*(N/4)[samples/spi]*bufsize + CLR reg_flags, reg_flags, FLAG_BIT_BUFFER1 // Bit 0 holds which buffer we are on + MOV r2, 0 + SBBO r2, reg_comm_addr, COMM_FRAME_COUNT, 4 // Start with frame count of 0 // Here we are out of sync by one TDM slot since the 0 word transmitted above will have occupied // the first output slot. Send one more word before jumping into the loop.