[SOLVED] Interface with I2C-bus controlled synthesizer (TSA5511)

Thanks again, bartjenniskens
I will read again about the flags for sure as i have all the datasheet in pdf.
Correct me if i am wrong but i realise that you agree with this troubleshooting that the problem is within PIC and not the TSA5511?
Last question, if i manage to read the existing PIC memory can i come back to you for advice?
Thanks in advance for your help.
Brgds
Dimis

Indeed, I would be suspicious about the PIC than I would be about the TSA5511.

Sure, but assembly is not my strongest point.

Many thanks i will keep you posted
Brgds
Dimi

Hi again, here is my latest actions.
please be informed that programming is neither my strongest point, i have purchase PICkit 3 that i have connect and using the MPLAB software after few corrective attempts i manage to read the PIC16F628A. Within i am able to see all memory partitions like Program memory, Configuration bits, EE data memory, User ID memory and Device ID memory.
It seams all are there as i found my name that was entered during previous normal operation. After read I try a Verify action and it comes with the following message.
Reading…

The following memory area(s) will be read:
program memory: start address = 0x0, end address = 0x7ff
configuration memory
EEData memory
User Id Memory
Read complete

Verifying…

The following memory areas(s) will be verified:
program memory: start address = 0x0, end address = 0x7ff
configuration memory
EEData memory
User Id Memory

Verification successful.

To my opinion it seams to be OK what do you believe?
I remain.
Dimis

Hi Dimis,

I’ve got a drfs06 exciter and it looks like the pic just died. I’ve got an empty pic laying around, but can’t find the firmware. Could you read out your pic and share the firmware?
I would really appreciate your help. Thank you!

Hi bartjenniskens,

I’ve got a pll fm transmitter in which the pic died. In case I can’t get the original firmware for the pic, could you share your .ino code so that I can build an alternative controller? I would really appreciate your help.

Thank you very much!

Off course, I’ll reply with the code to set the TSA5511

1 Like

Hi bartjenniskens, I don’t want to look like I’m impatient, but are you still gonna share your code?

Hey @lavao; Apologies for the delayed response, here is the full code. This code includes a 16x2 LCD display and 3 buttons. On the LCD the frequency and PLL Lock of the TSA5511 is shown, the buttons are used to set the frequency.

// This #include statement was automatically added by the Particle IDE.
#include <clickButton.h>

// This #include statement was automatically added by the Particle IDE.
#include <LiquidCrystal_I2C_Spark.h>

// Display settings
LiquidCrystal_I2C *lcd;

// General definations
# define button_menu_up D2
# define button_menu_set D3
# define button_menu_down D4
const int button_menu_up_Pin2 = 2;
const int button_menu_set_Pin3 = 3;
const int button_menu_down_Pin4 = 4;
ClickButton menu_up(button_menu_up_Pin2, LOW, CLICKBTN_PULLUP);
ClickButton menu_set(button_menu_set_Pin3, LOW, CLICKBTN_PULLUP);
ClickButton menu_down(button_menu_down_Pin4, LOW, CLICKBTN_PULLUP);

int function_menu_up = 0; // Button results 
int function_menu_set = 0; // Button results 
int function_menu_down = 0; // Button results 

// TSA5511 settings
# define tsa_addr_write 0x60 // normal 0xC0 but 0x60 because of 5 bits address (read wire lib why)
# define tsa_addr_read 0x60 // normal 0xC1 but 0x61 because of 5 bits address (read wire lib why)
bool readSensors = false; //Used in the loop to disable read-out when talking to the TSA5511
bool PLLWatchdog = false; //Action reading from I2C for LOCK flag at the TSA5511
uint32_t msLastMetric;
uint32_t msLastSample;
const uint32_t msSAMPLE_INTERVAL = 300; // 4 second interval

// EEPROM storage settings
int EEPROM_freq_addr = 10;

//Start freq when nothing is stored in the EEPROM
long freq = 87500000;

void setup() {
    // Setup button
    pinMode(button_menu_up, INPUT_PULLUP);
    pinMode(button_menu_set, INPUT_PULLUP);
    pinMode(button_menu_down, INPUT_PULLUP);
    
    //Setup wire and serial
    Wire.begin();        // join i2c bus (address optional for master)
    Serial.begin(115200);  // start serial for output

    // Setup LCD
    lcd = new LiquidCrystal_I2C(0x27, 16, 2);
    lcd->init();
    lcd->backlight();
    lcd->clear();
    display(0,0);
    delay(1000);

    // Initiate TSA5511
    TSAinit();
}

void loop() {

    //Read and actions on button clicks
    menu_up.Update();
    menu_set.Update();
    menu_down.Update();

    // Save click codes in LEDfunction, as click codes are reset at next Update()
    if(menu_up.clicks != 0) function_menu_up = menu_up.clicks;
    if(menu_set.clicks != 0) function_menu_set = menu_set.clicks;
    if(menu_down.clicks != 0) function_menu_down = menu_down.clicks;
    
    //UP - SINGLE click
    if(function_menu_up == 1) { 
        menu2(1); 
    };

    //DOWN - SINGLE click
    if(function_menu_down == 1) {
        menu2(2);
    };
    
    //SET - SINGLE click
    if(function_menu_set == 1) {
        menu2(0);
    }   
 
    function_menu_up = 0;
    function_menu_set = 0;
    function_menu_down = 0;

    //TSA5511 status loop
    if (PLLWatchdog == true){
        if (millis() - msLastSample >= msSAMPLE_INTERVAL){
            bool PLLLock = readPLLLockOnly();
            if (PLLLock == 1){
                // 1: TSA5511 Output port CP LOW and rest low = 0xCE + 0x00
                byte data[2];
                data[0] = 0xCE;
                data[1] = 0x24;
                Wire.beginTransmission(tsa_addr_write);
                Wire.write(data, 2);
                Wire.endTransmission();
                
                //Write frequency again.. or not
                byte datafreq[2];
                long Xtal = 3200000; //3.2Mhz crystal attached to TSA5511
                long fRef = Xtal / 512; //Reference devider
                long fDiv = freq / 8; // RF input devider
                long divider = fDiv / fRef;
                datafreq[0] = (divider & 0xFF00) >> 8;
                datafreq[1] = divider & 0x00FF;
                byte reg_addr = 0xCE;
                //byte tsa_addr = 0x60; // normal 0xC0 but 0x60 because of 5 bits address
            
                Wire.beginTransmission(tsa_addr_write);
                Wire.write(datafreq, 2);
                Wire.endTransmission();
                PLLWatchdog = false;
            }
        }
    }

}

void menu2(int menuMode){
    switch(menuMode){
        //MENU 1 - UP pushed
        case 1:
            freqSet(freq, 1);
            //menuChange = 1;
        break;
        
        //MENU 1 - DOWN pushed
        case 2:
            freqSet(freq, 2);
            //menuChange = 1;
        break;
        
        //MENU 1 - SET pushed
        case 0:
            freqSet(0,3);
            //menuChange = 0;
        break;
    }
}

void TSAinit(){
    Serial.println("## TSAinit ##");
    
    //Get last stored frequency from EEPROM
    uint16_t value;
    EEPROM.get(EEPROM_freq_addr, value);
    if(value == 0xFFFF) {
        // EEPROM was empty -> initialize default freq value
        freqStore(freq/100000);
        Serial.print("No frequency stored, storing default: ");Serial.println(freq);
    }
    Serial.print("Initializing frequency is: ");Serial.println(value);
    freq = value*100000;

    // Initialise the TSA5511 chip
    // 1: Set CP to HIGH and the rest to LOW
    // 2: Write frequency
    // 3: Start the PLL Watchdog
    
    // 1: TSA5511 Output port CP HIGH and rest low = 0xCE + 0x00
    byte data[2];
    data[0] = 0xCE;
    data[1] = 0x00;
    Wire.beginTransmission(tsa_addr_write);
    Wire.write(data, 2);
    Wire.endTransmission();

    // 2: Write frequency
    byte datafreq[2];
    long Xtal = 3200000; //3.2Mhz crystal attached to TSA5511
    long fRef = Xtal / 512; //Reference devider
    long fDiv = freq / 8; // RF input devider
    long divider = fDiv / fRef;
    datafreq[0] = (divider & 0xFF00) >> 8;
    datafreq[1] = divider & 0x00FF;
    Wire.beginTransmission(tsa_addr_write);
    Wire.write(datafreq, 2);
    Wire.endTransmission();

    Serial.print("write address: "); Serial.println(tsa_addr_write,HEX);
    Serial.print("data: "); Serial.print(data[0],HEX); Serial.print(" + ");  Serial.println(data[1],HEX);
    display(99,0);
    delay(300);
    
    PLLWatchdog = true;
    readSensors = true;
}

void freqSet(long freqInput, int set){
    switch(set){
        //Counts frequency up or down by pressing buttons
        case 0:
            freq = freqInput;
            freqWrite();
            display(96,0);
        break;
        case 1:
            freq = freqInput + 50000;
            if (freq == 108050000){ freq = 87500000;}
            display(97,freq);
            display(98,0);
            readSensors = false;
        break;
        case 2:
            freq = freqInput - 50000;
            if (freq == 87450000){ freq = 108000000;}
            display(97,freq);
            display(98,0);
            readSensors = false;
        break;
        case 3:
            freqWrite();
            display(96,0);
            delay(1000);
            display(3,readPLLLock());
            writeTSA5511P5down();
            readSensors = true;
        break;
    }
}

void freqWrite(){
    // 1: TSA5511 Output port CP HIGH and rest low = 0xCE + 0x00
    byte data[2];
    data[0] = 0xCE;
    data[1] = 0x00;
    Wire.beginTransmission(tsa_addr_write);
    Wire.write(data, 2);
    Wire.endTransmission();

    // 2: Write frequency
    byte datafreq[2];
    long Xtal = 3200000; //3.2Mhz crystal attached to TSA5511
    long fRef = Xtal / 512; //Reference devider
    long fDiv = freq / 8; // RF input devider
    long divider = fDiv / fRef;
    datafreq[0] = (divider & 0xFF00) >> 8;
    datafreq[1] = divider & 0x00FF;
    Wire.beginTransmission(tsa_addr_write);
    Wire.write(datafreq, 2);
    Wire.endTransmission();

    Serial.print("write address: "); Serial.println(tsa_addr_write,HEX);
    Serial.print("data: "); Serial.print(data[0],HEX); Serial.print(" + ");  Serial.println(data[1],HEX);
    freqStore(freq/100000);
    delay(100);

    PLLWatchdog = true;
}

void chargePump(){
    //Reset to 1100 1110
    //Reset is used before writing frequency and waiting for lock
    Serial.print("## chargepump ##");
    byte data[2];
    //TSA5511 Output port P5 high = 0xCE + 0x20
    data[0] = 0xCE; //CP high
    data[1] = 0x00; //P5 low
    
    Wire.beginTransmission(tsa_addr_write);
    Wire.write(data, 2);
    Wire.endTransmission();

    Serial.print("write address: "); Serial.println(tsa_addr_write,HEX);
    Serial.print("data: "); Serial.print(data[0],HEX); Serial.print(" + ");  Serial.println(data[1],HEX);
    delay(100);
}

void writeTSA5511P5down(){
    byte data[2];
    //TSA5511 Output port P5 to low
    data[0] = 0xCE; //CP high
    data[1] = 0x00; //P5 low
    
    Wire.beginTransmission(tsa_addr_write);
    Wire.write(data, 2);
    Wire.endTransmission();
}

void freqStore(uint16_t value){
    //Store frequency to internal EEPROM
    EEPROM.put(EEPROM_freq_addr, value);
}

int freqRead(){
    uint16_t value;
    EEPROM.get(EEPROM_freq_addr, value);
    return value*100000;
}

int readPLLLock(){
    int bitNumber = 6;
    int readByte = 0;
    int myBit = 0;
    
    Wire.requestFrom(tsa_addr_read, 1);    // request 1 byte from slave device
    delayMicroseconds(6);

    if (Wire.available()){  // wait for all data to arrive
        readByte = Wire.read();
        //Serial.printf("%02x ", readByte);
        Serial.print(" ");
        Serial.print(readByte, HEX);
        Serial.print("-");
        myBit = (readByte >> bitNumber) & 0x01;
        Serial.println(myBit);

        if (myBit == 1){
            //Af ther LOCK
            // - CP must be 1, T1 and T0, must be 0, OS must be 1 (HEX 0xCE)
            // - P5 must be high and turns on the LOCK LED on the PCB (Pin 8 on the TSA5511) and P2 must get high (Pin 11 on TSA5511) (HEX 0x24)
            byte data[2];
            data[0] = 0xCE;
            data[1] = 0x24;
            Wire.beginTransmission(tsa_addr_write);
            Wire.write(data, 2);
            Wire.endTransmission();
            
            //Write frequency again.. or not
            byte datafreq[2];
            long Xtal = 3200000; //3.2Mhz crystal attached to the TSA5511
            long fRef = Xtal / 512; //Reference devider
            long fDiv = freq / 8; // RF input devider
            long divider = fDiv / fRef;
            datafreq[0] = (divider & 0xFF00) >> 8;
            datafreq[1] = divider & 0x00FF;
            byte reg_addr = 0xCE;
            //byte tsa_addr = 0x60; // normal 0xC0 but 0x60 because of 5 bits address
        
            Wire.beginTransmission(tsa_addr_write);
            Wire.write(datafreq, 2);
            Wire.endTransmission();
        } else {
            chargePump();
        }
    } else {
        //nothing
    }
    return myBit;
}

int readPLLLockOnly(){
    int bitNumber = 6;
    int readByte = 0;
    int myBit = 0;
    
    Wire.requestFrom(tsa_addr_read, 1);    // request 1 byte from slave device
    delayMicroseconds(6);

    if (Wire.available()){  // wait for all data to arrive
        readByte = Wire.read();
        myBit = (readByte >> bitNumber) & 0x01;
        display(3,myBit);
    }
    return myBit;
}

void display(int mode, int data) {
    switch(mode){
        //Startup TSA5511
        case 1:
            lcd->clear();
            lcd->setCursor(0,0);
            lcd->print("Initializing TSA5511");
        break;
        //frequency change 
        case 2:
            freq = data;
            freqStore(freq/100000);
            
            //Display frequency
            lcd->setCursor(0,1);
            float displFreq;
            displFreq = (float)freq / 1000000.00;
            lcd->print(displFreq);
            if (displFreq > 99.95){ lcd->setCursor(6,1); } else { lcd->setCursor(5,1); }
            lcd->print("Mhz");
        break;
        
        //PLL lock
        case 3:
            lcd->setCursor(0,1);
            lcd->print("PLL:");
            lcd->setCursor(4,1);;
            if (data == 1){
                lcd->print("yes");
            } else {
                lcd->print("no ");
            }
        break;
        
        case 4:
            lcd->setCursor(14,1);
            lcd->print(data);
        break;
        
        //Menu 1 - frequence set
        case 11:
            lcd->clear();
            lcd->setCursor(6,0);
            lcd->print("PARTICLE-FM");
            lcd->setCursor(0,1);
            lcd->print("Menu: 1 - set freq");
            lcd->setCursor(0,1);
            displFreq = (float)freq / 1000000.00;
            lcd->print(displFreq);
            if (displFreq > 99.95){ lcd->setCursor(6,1); } else { lcd->setCursor(5,1); }
            lcd->print("Mhz ");
        break;
        
        //Menu 2 - Menu set
        case 12:
            lcd->clear();
            lcd->setCursor(6,0);
            lcd->print("PARTICLE-FM");
            lcd->setCursor(0,1);
            lcd->print("Menu: 2 - set");
        break;

        //removing changed note
        case 96:
            display(99,0);
        break;

        case 97:
            lcd->clear();
            //Line 1
            lcd->setCursor(0,0);
            lcd->print("Setting freq..");
            
            //Line 2
            //Display frequency
            lcd->setCursor(0,1);
            lcd->print("Freq: ");
            lcd->setCursor(6,1);
            displFreq = (float)freq / 1000000.00;
            lcd->print(displFreq);
            if (displFreq > 99.95){ lcd->setCursor(12,1); } else { lcd->setCursor(11,1); }
            lcd->print("Mhz");
        break;
        
        //setting changed note
        case 98:
            lcd->setCursor(15,0);
            lcd->print("*");
        break;
        
        //Home screen
        case 99:
            lcd->clear();

            //Line 1
            //Display frequency
            lcd->setCursor(0,0);
            lcd->print("Freq: ");
            lcd->setCursor(6,0);
            displFreq = (float)freq / 1000000.00;
            lcd->print(displFreq);
            if (displFreq > 99.95){ lcd->setCursor(12,0); } else { lcd->setCursor(11,0); }
            lcd->print("Mhz");

            //Line 2
            lcd->setCursor(0,1);
            lcd->print("PLL:");
            lcd->setCursor(5,1);
            lcd->print(readPLLLock());
        break;    
        case 0:
            //default (sets display after boot)
            lcd->setCursor(0,0);
            lcd->print("Starting...");
            lcd->setCursor(3,1);
            lcd->print("PARTICLE-FM");
        break;
    }
}```

hello with what program is compiled, is it for arduino?

No, it is for Particle products using their toolchains.

1 Like