Tuesday, 25 August 2009

dsPIC and DSP audio filter addition to QRP project

OK played abut a bit more with the PIC 16F877A and got most of the commands working for the VFO, dropping the dual VFO for the moment as think might have to go to dual PICs for that.

In the meantime looking at dsPIC capabilities and designed a first filter. 400Hz to 2.8KHz band width, using a P30F4013 (as have one!). This might go nowhere...


' Author M1KTA, dombaines@yahoo.com
' Date/Time: 25/08/2009 13:36:28
' Device setup:
' Device name: P30F4013
' Device clock: 080.000000 MHz
' Sampling Frequency: 20000 Hz
' Filter setup:
' Filter kind: FIR
' Filter type: Bandpass filter
' Filter order: 20
' Filter window: Rectangular
' Filter borders:
' Wp1: 400 Hz
' Wp2: 2800 Hz

const
BUFFER_SIZE = 32
FILTER_ORDER = 20
COEFF_B as Word[FILTER_ORDER+1] = (
0xFD0A, 0x00D8, 0xFE5F, 0xF592, 0xEB3C, 0xE6EC,
0xEEB0, 0x0316, 0x1DE4, 0x3493, 0x3D71, 0x3493,
0x1DE4, 0x0316, 0xEEB0, 0xE6EC, 0xEB3C, 0xF592,
0xFE5F, 0x00D8, 0xFD0A)

LOAD_PIN = 4 ' DAC load pin
CS_PIN = 5 ' DAC CS pin

dim
inext as Word ' Input buffer index
input_ as Word[BUFFER_SIZE] ' Input buffer

' This is ADC interrupt handler.
' Analogue input is sampled and the value is stored into input buffer.
' Input buffer is then passed through filter.
' Finally, the resulting output sample is sent to DAC.
sub procedure ADC1Int org $2A ' ADC interrupt handler
dim CurrentValue as word

input_[inext] = ADCBUF0 ' Fetch sample

CurrentValue = FIR_Radix(FILTER_ORDER+1,' Filter order
@COEFF_B, ' b coefficients of the filter
BUFFER_SIZE, ' Input buffer length
@input_, ' Input buffer
inext) ' Current sample

inext = (inext+1) and (BUFFER_SIZE-1) ' inext := (inext + 1) mod BUFFFER_SIZE;

while SPI1STAT.1 = 1 'wait for SPI module to finish, if doing something
nop
wend
LATF.CS_PIN = 0 ' CS enable for DAC
SPI1BUF = $3000 or CurrentValue ' Write CurrentValue to DAC ($3 is required by DAC)
while SPI1STAT.1 = 1 ' Wait for SPI module to finish write
nop
wend
LATF.LOAD_PIN = 0 ' Load data in DAC
LATF.LOAD_PIN = 1 '
LATF.CS_PIN = 1 ' CS disable for DAC

IFS0.11 = 0 ' Clear AD1IF
end sub

' This is Timer1 interrupt handler.
' It is used to start ADC at
' periodic intervals.
sub procedure Timer1Int org $1A ' Timer1 interrupt handler

ADCON1.1 = 1 ' Start sampling
ADCON1.15 = 1 ' Start conversion

IFS0.3 = 0 ' Clear TMR1IF
end sub


' Main program starts here.
' Firstly, hardware peripherals are initialized and then
' the program goes to an infinite loop, waiting for interrupts.
main:
' DAC setup
TRISF.LOAD_PIN = 0 ' LOAD pin
TRISF.CS_PIN = 0 ' CS pin
LATF.CS_PIN = 1 ' Set CS to inactive
LATF.LOAD_PIN = 1 ' Set LOAD to inactive

' SPI setup
SPI1_Init_Advanced(_SPI_MASTER, _SPI_16_BIT, _SPI_PRESCALE_SEC_1, _SPI_PRESCALE_PRI_1,
_SPI_SS_DISABLE, _SPI_DATA_SAMPLE_MIDDLE, _SPI_CLK_IDLE_HIGH,
_SPI_ACTIVE_2_IDLE)

inext = 0 ' Initialize buffer index
Vector_Set(input_, BUFFER_SIZE, 0) ' Clear input buffer

' ADC setup
TRISB = $FFFF ' Use PORTB for input signal
ADCON1 = $00E2 ' Auto-stop sampling, unsigned integer out
ADCON2 = $0000
ADCON3 = $021A ' Sampling time= 3*Tad, minimum Tad selected
ADPCFG = $0000 ' Configure PORTB as ADC input port
ADCHS = $000A ' Sample input on RB10
ADCSSL = 0 ' No input scan

' Interrupts setup
IFS0 = 0
IFS1 = 0
IFS2 = 0
INTCON1 = $8000 ' Nested interrupts DISABLED
INTCON2 = 0
IEC0 = $0808 ' Timer1 and ADC interrupts ENABLED
IPC0.12 = 1 ' Timer1 interrupt priority level = 1
IPC2.13 = 1 ' ADC interrupt priority level = 2

' Timer2 setup
PR1 = $03E8 ' Sampling = 20000 Hz. Value of PR1 is dependent on clock.
T1CON = $8000 ' Timer1 ON, internal clock FCY, prescaler 1:1

while true ' Infinite loop,
nop ' wait for interrupts
wend
end.

No comments:

Post a Comment