diyAudio

diyAudio (http://www.diyaudio.com/forums/)
-   Analog Line Level (http://www.diyaudio.com/forums/analog-line-level/)
-   -   PGA2311 code (http://www.diyaudio.com/forums/analog-line-level/228382-pga2311-code.html)

child1 22nd January 2013 07:13 AM

PGA2311 code
 
3 Attachment(s)
Hi everyone!

I'm having trouble getting my PGA2311 to work. I have an ATTINY2313 controlling it, but i can't control the volume. Would anyone be so kind as to go through my code (attached) and look for an explanation as to why it wont work.

Thank you!

Best regards

Mads, Denmark

jan.didden 22nd January 2013 08:48 AM

Can't see anything wrong.
I wonder though why the long delays in the clocking sequence?
I've done this with a PIC with a 1uS instruction cycle with no delays, reliably.
One thing you can verify is whether the Mute pin is actually set correctly.
Only advise I have is to spend some money for a low cost USB logic analyzer like the Saelig but there are more even lower in cost that do 8 bits. Pays for it very quickly!

jan

child1 22nd January 2013 08:56 AM

Thanks for the reply. The reason for the long delays is that I tried with faster delays and that didn't work, so I thought I'd give it a go with longer delays, but no difference. So to answer your question - there is no reason for the long delays... :)

The mute pin is high on startup and throughout the tests I've made, so that should be right!

It's really starting to annoy me, why it won't work... :( But hopefully someday I will find the error.... :)

theAnonymous1 22nd January 2013 09:18 AM

Maybe looking at the code for this project can help...

MiniVol PGA2320 Volume Control - error404's Audio DIY Endeavours

rsavas 24th January 2013 07:32 PM

I have BASCOM-AVR code that I can share with you. It is written for an xmega and has a 4x40 LCD display. The basic building blocks for pre-amp/tuner

Config Portc.4 = Output
Pga_cs Alias Portc.4
Set Pga_cs 'Slave Select Pin, Connect to PGA2311-2 (CS), active low
'Dim Select_bit As Bit
'Portc_pin0ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
'Portc_pin1ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
'Portc_pin2ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
'Portc_pin3ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
Portc_pin4ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
Portc_pin5ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
Portc_pin7ctrl = &B10_011_010 ' slew, no invert, Totempole, Pull-up (on input),Sense falling edge
Config Spic = Hard , Master = Yes , Mode = 0 , Clockdiv = Clk32 , Data_order = Msb , Ss = None
Open "SPIC" For Binary As #3

If Encoder2old <> Encoder2 Then 'Use for Volume/Balance Function
If Pga2311_mute = 1 Then '
Volume_count = Encoder2
Encoder2old = 0
Encoder2 = 0
Volume = Volume + Volume_count
'Volume_L = Volume_L + Volume_count
'Volume_R = Volume_R + Volume_count
Disable Interrupts
Encoder2old = Encoder2
Enable Interrupts
'If Volume_L > 212 Then Volume = 212
'If Volume_R > 212 Then Volume = 212
If Volume > Volume_max Then Volume = Volume_max 'Volume Limit, max 255
If Volume < 0 Then Volume = 0
'If Volume_L < 0 Then Volume_L = 0
'If Volume_R < 0 Then Volume_R = 0
Volume_s = Volume
Volume_s = 255 - Volume_s
Volume_s = Volume_s / 2
Volume_s = 31.5 - Volume_s '31.5 -(0.5 *(255 - N))
___lcde = 1
Locate 1 , 1
'Lcd "****************************************"
Lcd "Volume L = "
Locate 1 , 12
Lcd Fusing(volume_s , "#.#") ; " dB "
Locate 1 , 21
Lcd "R = "
Lcd Fusing(volume_s , "#.#") ; " dB"
'Dim Volume_word As Word
'Dim V_right As Byte At Volume_word Overlay
'Dim V_left As Byte At Volume_word + 1 Overlay
V_right = Volume 'Assemble word for PGA2311
V_left = Volume 'Need to add balance function
Reset Pga_cs 'Select SPI Slave
Print #3 , Volume_word 'Send 16 bits to PGA2310
Set Pga_cs 'Deselect SPI Slave
End If
End If

send me a PM if you want my test code!!

Bonsai 25th January 2013 11:37 AM

Let me dig mine out this weekend and you can take a look at that also.

rollingtube 25th January 2013 12:35 PM

Hi,

couple questions -
- are the interrupt routines that move volume up or down really called via INT0/INT1?
- if they aren't, during init you set /MUTE to 0, that means you mute the device - so I assume you measured that the pin is set to 1 during normal operation (just to reconfirm, as I don't see how the interrupts are called)
- you start with -86dB and only allow -33.5db max - is that intended? Do you check volume via the out put signal on an oscilloscope, or do you only listen? Is your source line level high enough to be audible at -33.5db?

Not sure if it matters, but on my implementation I left the clock on logical "1" when the SPI was not transmitting. (I did use the build-in serial transmitter on the 2313 in Assembler, so not possible to directly compare the code...)

child1 25th January 2013 06:17 PM

Hi everyone ! Thanks for all your replies!

@rsavas - unfortunately, I have no experience at all with bascom but will take a look non the less... :)

@bonsai - Sounds great!

@rollingtube - the subroutines are called from int0/int1 on any logical change using an rentron TINY IR-II IR decoder (or at least that was what is supposed to happen ;))
The Mute set to 0 during init is a mistake, which have been changed :)
Also the max -33.5dB has been changed to unity gain (0dB) but with no difference.
I haven't checked the output signal on a oscilloscope yet, but will do this monday!
So sorry guys, despite all your help, the solution is not yet found.. :S But I will keep
on going 'till i find it!

Thanks for all your help! just keep it comming :)

- Mads

rsavas 26th January 2013 02:27 PM

BASCOM-AVR= dead simple, this is why I selected this compiler over gcc!! Free demo available, all you need is a AVRISP mkII and some HW.
My first HW was a xmega BOB and the following mounted on a proto-board: from this basic setup I got my feet wet and then designed my product there-after. My test code is now at line 2357, so I can give this to you for free!! It is a lot of code, so I do not want to post it all here, but the small bit of code i have posted here, will give you an idea of how easy it really is.
The product is much more code, but I will not be releasing that, as it is of no use, as it is, unless you have the HW. If you are interested in my HW we can talk off line.

' Hardware: Sparkfun xmega100 BOB
' Newhaven NHD-0440AZ-FL-YBW
' PGA2310
' PCA9555
' 3x Bourns PC12 rotary encocders with switches
' 6x spst switches with LED (C&K K5V-BU)
' DSS BMP180
' Honeywell HumidIcon Digital Humidity/Temperature Sensor: HIH-6130/6131 Series
Dim Volume_word As Word 'Word to be written to PGA2310/2320/2311

Dim V_right As Byte At Volume_word Overlay
Dim V_left As Byte At Volume_word + 1 Overlay
Config Portk = Input
Config Portk.6 = Output 'PGA2311 Mute, active Low
Set Portk.6
Pga2311_mute Alias Portk.6

Config Portk.7 = Output 'PGA2311 ZEN, active High
Pga2311_zen Alias Portk.7
Reset Portk.7

Config Portc.4 = Output
Pga_cs Alias Portc.4

'This is all it takes to write to the PGA part
Reset Pga_cs 'Select SPI Slave
Print #3 , Volume_word 'Send 16 bits to PGA2310/11/20
Set Pga_cs 'Deselect SPI Slave

counter culture 26th January 2013 07:35 PM

I'm not an AVR programmer, so it's difficult for me to be sure what's going on here, but I have done this with a PIC, both in assembler and in C.

First of all, I don't understand why you are doing this using interrupts.

Interrupts are always much more difficult to debug than polling loops, and you don't need interrupts to make this work. I'd rewrite the whole thing without the interrupts. I used the timer interrupts to drive a multiplexed 7-segment LED array, that's a different matter, I needed them then.

What does this:-

Code:

    PCMSK |= (1<<PCINT0); // Enable PCINT0 on PB0
...do?

PCMSK gets PCMSK bitwise OR'ed with what? What does (1<<PCINT0) mean? PCINT0 is left shifted once? One is left shifted PCINT0 times? The shift operators syntax is normally (x<<2) (x left shifted twice). Maybe AVR c is different... What is PCINT0? Why do you want to left shift it? I can see what INT0 is, I can see what PCINT is, you've got 3 ISRs INT0, INT1, and PCINT.

????????

You need to avoid comparatively obscure forms of coding like this. I've been coding in C for at least 20 years, it took me half-an-hour to figure out what it means... It's probably not your fault, you probably copied it from some smartass AVR example code.

It sets the bit called PCINT0, the one for PORTB, bit 0, in the interrupt SFR. PCINT0 is an alias for the bit number. Yes? The associated interrupt is INT0, so the ISR is passed INT0_vect?

What was wrong with

Code:

    sbi (PCMSK, PCINT0);
...??? I'd have got that immediately.

Write straightforward code where it is easy to see explicitly what is taking place. Don't combine multiple operations in a single instruction.

You have this:-

Code:

        //Enable mute
        PORTB &= 0b11111101;

and this:-

Code:

        // Disable mute
        PORTB |= (1<<PB1);

... if you want to disable the mute pin (force it to 1), write this:-

Code:

        PORTB |= 0b00000010;
or this:-

Code:

      sbi (PORTB, 1);
I can't see any point where you enable INT1 or PCINT. Presumably they are on other pins of PORTB?

What is PCINT? Why isn't it called INT3 and assigned a bit on PORTB? Is is a special feature of AVRs I can't figure out without reading the manual?

You don't need 3 files. You can keep all this stuff in 1 file. Having it in 3 files just makes it hard to read.

Code:

#include "Volume.h"
#include "avr/io.h"
#include "compat/deprecated.h"
#define F_CPU 1000000UL
#include "avr/delay.h"

int main(void);
int PGA_volume(unsigned char volume_r, unsigned char volume_l);
ISR(INT0_vect);
ISR(INT1_vect);
ISR(PCINT_vect);

unsigned char left, right;

int main(void)
{       
    DDRB = 0xFF;                                        // Port B as output
    GIMSK |= 0b11100000;                                  // Initialize interrupts
    MCUCR |= 0b00000101;                                // interrupt on any logical change
    PCMSK |= (1<<PCINT0);                              // Enable PCINT0 on PB0       
    PORTB |= (1<<PB7);                                  // enable ZCEN
    PORTB &= 0b11111101;                                // disable mute       
    left = 20;
    right = 20;
       
    PGA_volume(right, left);       
    while(1)
    {
        sei();                                          // Enable global interrupts
    }               
}

int PGA_volume(unsigned char volume_r, unsigned char volume_l)
{
        unsigned char i;
        unsigned char send_r, send_l;

        cbi (PORTB, 6);                                // Enable chip select
        for(i = 0 ; i < 8 ; i++)                        // Send volume right
        {
                send_r = volume_r & 0x80;
                if (send_r == 0x80)
                {
                        sbi (PORTB, 5);                // Set bit data
                        _delay_us(100);
                        sbi (PORTB, 2);                // Set bit clock
                        _delay_us(50);
                        cbi (PORTB, 2);                // Clear bit clock
                        _delay_us(50);
                }

                if (send_r == 0x00)
                {
                        cbi (PORTB, 5);
                        _delay_us(100);
                        sbi (PORTB, 2);
                        _delay_us(50);
                        cbi (PORTB, 2);
                        _delay_us(50);
                }
                volume_r = volume_r << 1;
        }
        for(i = 0 ; i < 8 ; i++)                        // Send volume left
        {
                send_l = volume_l & 0x80;

                if (send_l == 0x80)
                {
                        sbi (PORTB, 5);
                        _delay_us(100);
                        sbi (PORTB, 2);
                        _delay_us(50);
                        cbi (PORTB, 2);
                        _delay_us(50);
                }

                if (send_l == 0x00)
                {
                        cbi (PORTB, 5);
                        _delay_us(100);
                        sbi (PORTB, 2);
                        _delay_us(50);
                        cbi (PORTB, 2);
                        _delay_us(50);
                }
                volume_l = volume_l << 1;
        }
        sbi (PORTB, 6);                                // Disable chip select
        cbi (PORTB, 5);                                // Clear bit data
        cbi (PORTB, 2);                                // Clear bit clock
        return;
}

ISR(INT0_vect)                                          // Increment volume
{               
        // Disable mute
        PORTB |= (1<<PB1);
        if(left > 125 | right > 125)
        {
                left = 125;
                right = 125;
        }
        else
        {
                left = left + 1;
                right = right + 1;
        }
        PGA_volume(right,left);
}


ISR(INT1_vect)                                          // Decrement volume
{
        // Disable mute
        PORTB |= (1<<PB1);
        if(left > 125 | right > 125)
        {
                left = 125;
                right = 125;
        }
        else
        {
        left = left - 1;
        right = right - 1;
        }       
        PGA_volume(right,left);
}


ISR(PCINT_vect)                                        // Mute volume
{
        //Enable mute
        PORTB &= 0b11111101;
}

Now I can search the whole of the code in one operation for PCINT...

As far as I can tell, you've only enabled interrupts on one of the pins, that can't be helping. If the mute is on PORTB,1 which pin is calling the interrupt for INT1?


All times are GMT. The time now is 03:29 PM.


vBulletin Optimisation provided by vB Optimise (Pro) - vBulletin Mods & Addons Copyright © 2014 DragonByte Technologies Ltd.
Copyright 1999-2014 diyAudio


Content Relevant URLs by vBSEO 3.3.2