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
Programming 12C508A
-
- Neckmin
- Posts: 338
- Joined: Fri Oct 17, 2014 10:35 am
Re: Programming 12C508A
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.
-
- proppa neck!
- Posts: 537
- Joined: Mon Sep 02, 2019 11:06 am
Re: Programming 12C508A
Thanks NRG. ill have a play with that.
-
- Neckmin
- Posts: 338
- Joined: Fri Oct 17, 2014 10:35 am
Re: Programming 12C508A
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
and the spi library you'll also need to include in your project
spi.h
spi.c
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;
}
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 */
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
}
-
- Neckmin
- Posts: 338
- Joined: Fri Oct 17, 2014 10:35 am
Re: Programming 12C508A
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.
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.