Programming 12C508A

Everything technical about radio can be discussed here, whether it's transmitting or receiving. Guides, charts, diagrams, etc. are all welcome.
Post Reply
XXL
proppa neck!
proppa neck!
Posts: 537
Joined: Mon Sep 02, 2019 11:06 am

Programming 12C508A

Post by XXL » Wed Jan 22, 2020 1:01 am

I need to program this device to work as a divider with the mc145170. I have no clue how to write a script for micro controllers so im at a stalemate. Does anyone use a piece of software that would write and build the hex file for you ? This device is widely used and I cant see many people being able to write code for this. The reference frequency is 4mhz. This script was taken from another site.

_______________________________________________________________________________________________

include p12F629.inc

Dout equ 0x00
Dout_port equ GPIO

Enb equ 0x04
Enb_port equ GPIO

Clk equ 0x05
Clk_port equ GPIO


Clock_count equ 0x20
Out_data_2 equ 0x21
Out_data_1 equ 0x22
Out_data_0 equ 0x23

clock_count2 equ 0x24
Out_data_2_b equ 0x25
Out_data_1_b equ 0x26
Out_data_0_b equ 0x27


org 0

clrf Clock_count

decfsz clock_count2, f
goto $-1

decfsz Clock_count, f
goto $-3 ;startup pause


movlw 0x07
movwf CMCON ;turn off comparators

bsf STATUS, RP0 ;go to bank 1

bcf Enb_port, Enb
bcf Dout_port, Dout
bcf Clk_port, Clk ;enable the outputs

bcf STATUS, RP0 ;back to bank 0

bsf Enb_port, Enb ;start off with the enable line high
bcf Clk_port, Clk ;and the clock low

clrf Clock_count

decfsz clock_count2, f
goto $-1

decfsz Clock_count, f
goto $-3 ;pause to make sure the PLL has started

call reset_PLL



reset_PLL
;With the data line low, and the enable line high
;this needs to clock out 4 cycles

bcf Dout_port, Dout
bsf Enb_port, Enb

movlw 0x04
movwf Clock_count

reset_clock_loop
bsf Clk_port, Clk
nop
bcf Clk_port, Clk

decfsz Clock_count, f
goto reset_clock_loop

movlw 0x05
movwf Clock_count

movlw 0x02
movwf Out_data_0

call data_out ;clock out the remaining 5 bits of the reset sequence

;This outputs 0 to the configuration register
;That is the default so it does nothing but it's here so that other numbers can be output

movlw 0b00000000
movwf Out_data_0

movlw 0x08
movwf Clock_count

call data_out

;This now outputs 80 to the reference divider.
;The 15 clock cycles cause it to be addressed to the reference divider
;With a 4 MHz reference and a resolution of 50 kHz, the reference needs to be divided by 80

movlw 0x0f
movwf Clock_count

movlw 0
movwf Out_data_1

movlw 0x50
movwf Out_data_0

call data_out

;Now this outputs 2140 to the frequency divider.
;The 16 clock cycles cause it to be addressed to the frequency divider
;2140 x 50 kHz = 107 MHz

movlw 0x10
movwf Clock_count

movlw 0x08
movwf Out_data_1

movlw 0x5C ;there might be a neat way of getting the assembler
; to split 2140 into two bytes.
movwf Out_data_0

call data_out

;that's it
;All the program does now is die
goto $ ;This needs the watchdog to be disabled


data_out
;the data needs to be msb first, but the length of the data varies.
;So it has to be reversed first

movf Clock_count, w
movwf clock_count2

data_reverse_loop
;This reverses the Clock_count bits of data into Out_data_n_b
;so that the MSB ends up in the LSB of Out_data_0_b
rrf Out_data_2, f
rrf Out_data_1, f
rrf Out_data_0, f ;rotate data towards LSB

rlf Out_data_0_b, f
rlf Out_data_1_b, f
rlf Out_data_2_b, f ;rotate data towards MSB

decfsz clock_count2, f
goto data_reverse_loop


movwf clock_count2 ;collect count again from w

bcf Enb_port, Enb ;lower enable line

data_out_loop
;This output data starting with the LSB of Out_data_0_b

btfsc Out_data_0_b, 0
bsf Dout_port, Dout

btfss Out_data_0_b, 0
bcf Dout_port, Dout ;output data

rrf Out_data_2_b, f
rrf Out_data_1_b, f
rrf Out_data_0_b, f ;rotate data to LSB

bsf Clk_port, Clk
nop
bcf Clk_port, Clk ;clock data into PLL

decfsz clock_count2, f
goto data_out_loop

bsf Enb_port, Enb ;raise enable line to save data

return

end

nrgkits.nz
Neckmin
Neckmin
Posts: 337
Joined: Fri Oct 17, 2014 10:35 am

Re: Programming 12C508A

Post by nrgkits.nz » Wed Jan 22, 2020 10:08 am

Use XC8 and Mplab IDE, it’s far easier than using assembler. It’s not difficult to write code for the MC145170, this PLL chip uses SPI and the data sheet will show you which bits to use to program the device and set the divider. I have several lots of code I’ve written for this device - I’ll post some up tomorrow.

XXL
proppa neck!
proppa neck!
Posts: 537
Joined: Mon Sep 02, 2019 11:06 am

Re: Programming 12C508A

Post by XXL » Wed Jan 22, 2020 7:53 pm

Thanks NRG. ill have a play with that.

nrgkits.nz
Neckmin
Neckmin
Posts: 337
Joined: Fri Oct 17, 2014 10:35 am

Re: Programming 12C508A

Post by nrgkits.nz » Fri Jan 24, 2020 10:43 am

Here's the XC8 routine I use to program the MC145170. Most of the PIC16F series PIC's should work as long as they have SPI registers

Code: Select all

void SetFreq(unsigned char mhz, unsigned char khz) { //Enter frequency in Hz, eg for 102.5MHz (mhz = 102000000, khz = 500000)

	unsigned long osc = 10000000; //10MHz reference
	unsigned long ref = 25000; //25KHz phase detector

	unsigned long Ndiv = (((( (unsigned long) mhz * 1000000 ) + ((unsigned long) khz * 10000 )) / ref);
	unsigned long Rdiv = osc / ref;

	SPI_SS = 0;
	__delay_ms(1);
	spiWrite(0b00100111);
	__delay_ms(1);
	SPI_SS = 1;

	__delay_ms(1);

	//configure R divider
	SPI_SS = 0;
	__delay_ms(1);

	spiWrite(0x00);
	spiWrite((Rdiv & 0xFF00) >> 8);
	spiWrite(Rdiv & 0x00FF);
	__delay_ms(1);
	SPI_SS = 1;

	__delay_ms(1);

	//configure N divider
	SPI_SS = 0;
	__delay_ms(1);
	spiWrite((Ndiv & 0xFF00) >> 8);
	spiWrite(Ndiv & 0x00FF);
	__delay_ms(1);
	SPI_SS = 1;

}
and the spi library you'll also need to include in your project

spi.h

Code: Select all

#ifndef SPI_H
#define	SPI_H

#include <xc.h> 

typedef enum 
{
    SPI_MASTER_OSC_DIV4  = 0b00100000,
    SPI_MASTER_OSC_DIV16 = 0b00100001,
    SPI_MASTER_OSC_DIV64 = 0b00100010,
    SPI_MASTER_TMR2      = 0b00100011,
    SPI_SLAVE_SS_EN      = 0b00100100,
    SPI_SLAVE_SS_DIS     = 0b00100101
}Spi_Type;

typedef enum
{
    SPI_DATA_SAMPLE_MIDDLE   = 0b00000000,
    SPI_DATA_SAMPLE_END      = 0b10000000
}Spi_Data_Sample;

typedef enum
{
    SPI_CLOCK_IDLE_HIGH  = 0b00010000,
    SPI_CLOCK_IDLE_LOW   = 0b00000000 
}Spi_Clock_Idle;

typedef enum
{
    SPI_IDLE_2_ACTIVE    = 0b00000000,
    SPI_ACTIVE_2_IDLE    = 0b01000000
}Spi_Transmit_Edge;


void spiInit(Spi_Type, Spi_Data_Sample, Spi_Clock_Idle, Spi_Transmit_Edge);
void spiWrite(char);
unsigned spiDataReady();
char spiRead();

#endif	/* SPI_H */
spi.c

Code: Select all

#include "spi.h"

void spiInit(Spi_Type sType, Spi_Data_Sample sDataSample, Spi_Clock_Idle sClockIdle, Spi_Transmit_Edge sTransmitEdge)
{
    TRISC5 = 0;
    if(sType & 0b00000100) //If Slave Mode
    {
        SSPSTAT = sTransmitEdge;
        TRISC3 = 1;
    }
    else              //If Master Mode
    {
        SSPSTAT = sDataSample | sTransmitEdge;
        TRISC3 = 0;
    }
    
    SSPCON = sType | sClockIdle;
}

static void spiReceiveWait()
{
    while ( !SSPSTATbits.BF ); // Wait for Data Receive complete
}

void spiWrite(char dat)  //Write data to SPI bus
{
    SSPBUF = dat;
}

unsigned spiDataReady() //Check whether the data is ready to read
{
    if(SSPSTATbits.BF)
        return 1;
    else
        return 0;
}

char spiRead() //REad the received data
{
    spiReceiveWait();        // wait until the all bits receive
    return(SSPBUF); // read the received data from the buffer
}

nrgkits.nz
Neckmin
Neckmin
Posts: 337
Joined: Fri Oct 17, 2014 10:35 am

Re: Programming 12C508A

Post by nrgkits.nz » Fri Jan 24, 2020 10:52 am

Also bare in mind that you *need* to have pull up resistors on each of the SPI lines (including slave select) otherwise you'll get unreliable communication between the two devices.

You'll also need to initialise the SPI in your main routine using:
spiInit(SPI_MASTER_OSC_DIV4, SPI_DATA_SAMPLE_MIDDLE, SPI_CLOCK_IDLE_LOW, SPI_ACTIVE_2_IDLE);

There's also other basic config on the PIC that needs to be done like setting the correct inputs and outputs using the TRIS registers etc... If you look at your PIC's datasheet its easy to do.

Post Reply