Hi! I have a cheap AD9850 module but I'm having troubles interfacing it with the FRDM-KL25Z board.
I found this mbed code:
AD9850-function-generator-SPI-driver - a mercurial repository | mbed
I tried it with my board and it works. I ported the code to a Coldfire V1 JM128 and it works, but when I try to port it to the FRDM-KL25Z with Codewarrior v10.6 it doesn't work... so I think I'm doing something wrong in the initialization of the peripherals.
Here is my code for the FRDM-KL25Z:
#include "derivative.h" /* include peripheral declarations */
#include "mcg.h"
#include "lptmr.h"
// PTA13 - Reset
// PTD0 - Chip Select
#define CS_ON GPIOD_PSOR = (1<<0)
#define CS_OFF GPIOD_PCOR = 1<<0
#define ADReset_ON GPIOA_PSOR = (1<<13)
#define ADReset_OFF GPIOA_PCOR = 1<13
unsigned long int reverseBits (unsigned long int source);
void SPI_InitMaster( void );
void writeSPI(unsigned long int frq, unsigned char phase);
void CLK_init(void);
int main(void)
{
SIM_COPC = SIM_COPC_COPT(0x00); /* Disable the WDOG module */
pll_init(8000000, LOW_POWER, CRYSTAL,4,24,MCGOUT); //Core Clock is now at 48MHz using the 8MHZ Crystal ((8MHz/4)*24)
lptmr_init(10000, 0);
SPI_InitMaster();
// This routine produces a continuous frequency sweep
unsigned long int targetFrq=0x147AE148; // Frequency word = ([Desired freq in MHz] * 34.3597384)
unsigned long int increment=0xD6B; //100Hz step
// Reset the AD9850. Active high logic. Minimum reset period 5 clock cycles (5/125MHz)
ADReset_OFF;
time_delay_ms(5);
ADReset_ON;
time_delay_ms(5);
ADReset_OFF;
for(;;) {
while (targetFrq<0x148bFFFF) // up to 10.001MHz
{
writeSPI(reverseBits(targetFrq),0); // Don't use phase so set to zero.
targetFrq=targetFrq+increment;
}
while (targetFrq>0x147AE148) // down to 10MHz
{
writeSPI(reverseBits(targetFrq),0);
targetFrq=targetFrq-increment;
}
}
return 0;
}
/****************************************************************
initial the spi module to master mode
*****************************************************************/
void SPI_InitMaster( void )
{
// enable clock gate for spi module
SIM_SCGC4 |= SIM_SCGC4_SPI0_MASK;
// enable PORT
SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK|SIM_SCGC5_PORTA_MASK;
// disable SPI
SPI0_C1 &= ~SPI_C1_SPE_MASK;
// configure I/O to SPI function
//PORTD_PCR0 &= ~PORT_PCR_MUX_MASK;
//PORTD_PCR0 |= PORT_PCR_MUX(2)|PORT_PCR_DSE_MASK; //Use PTD0 as SPI0_SS_b
PORTD_PCR0 = PORT_PCR_MUX(1) | PORT_PCR_DSE_MASK; //PTD0 es SS
PORTA_PCR13 = PORT_PCR_MUX(1) | PORT_PCR_DSE_MASK; //PTA13 es Reset
GPIOD_PDDR |= (1<<0);
GPIOA_PDDR |= (1<<13);
PORTD_PCR3 &= ~PORT_PCR_MUX_MASK;
PORTD_PCR3 |= PORT_PCR_MUX(2)|PORT_PCR_DSE_MASK; //Use PTD3 as SPI0_MISO
PORTD_PCR2 &= ~PORT_PCR_MUX_MASK;
PORTD_PCR2 |= PORT_PCR_MUX(2)|PORT_PCR_DSE_MASK; //Use PTD2 as SPI0_MOSI
PORTD_PCR1 &= ~PORT_PCR_MUX_MASK;
PORTD_PCR1 = PORT_PCR_MUX(2)|PORT_PCR_DSE_MASK; //Use PTD1 as SPI0_SCK
SPI0_C1 |= SPI_C1_MSTR_MASK;
SPI0_BR = 0b01010001; //Divido por 6 y despues por 4 entonces si el BUS CLK = 24 MHz, el SPI CLK = 1 MHz
//SPI0_C1 |= SPI_C1_SSOE_MASK;
//SPI0_C2 |= SPI_C2_MODFEN_MASK;
SPI0_C1 &= ~SPI_C1_SSOE_MASK;
SPI0_C2 &= ~SPI_C2_MODFEN_MASK;
//SPI0_C1 |= SPI_C1_CPHA_MASK;
SPI0_C1 &= (~SPI_C1_CPHA_MASK); //CPHA = 0
//SPI0_C1 |= SPI_C1_CPOL_MASK;
SPI0_C1 &= (~SPI_C1_CPOL_MASK); //CPOL = 0
//SPI0_C1 |= SPI_C1_LSBFE_MASK;
SPI0_C1 &= (~SPI_C1_LSBFE_MASK); //MSB
SPI0_C1 |= SPI_C1_SPE_MASK; //Activa SPI
}
unsigned long int reverseBits (unsigned long int source)
{
// Unfortunately need to invert bit order of the desired frequency setting since MBED only allows for MSB first from SPI. We need LSB first for AD9850
unsigned long int mask=0;;
int i=0;
unsigned long int target=0;
unsigned long int bitTarget=0x80000000; // Hard-wired for 32-bit inversion
for (i=0;i<32;i++) { // ditto
mask=1<<i;
bitTarget=1<<(31-i); // ditto
if (source & mask)
target=target | bitTarget;
}
return target;
}
void writeSPI(unsigned long int frq, unsigned char phase)
{
// Send the 40-bit packet. NB: KL25Z only supports 8-bit SPI so send five 8-bit packets
// First do chip select. Need to use a GPIO to fake the chip select since MBED doesn't allow to set positive logic CS signal
CS_ON; // assert chip select (a.k.a FQ_UD frequency update input to AD9850)
time_delay_ms(1);
CS_OFF;
while(!(SPI0_S & SPI_S_SPTEF_MASK ) )
{
asm("nop");
}
SPI0_D = frq>>24;
while(!(SPI0_S & SPI_S_SPTEF_MASK ) )
{
asm("nop");
}
SPI0_D = frq>>16;
while(!(SPI0_S & SPI_S_SPTEF_MASK ) )
{
asm("nop");
}
SPI0_D = frq>>8;
while(!(SPI0_S & SPI_S_SPTEF_MASK ) )
{
asm("nop");
}
SPI0_D = frq;
while(!(SPI0_S & SPI_S_SPTEF_MASK ) )
{
asm("nop");
}
SPI0_D = phase;
// Now pulse FQ_UD again to load the word into the DDS
CS_OFF;
time_delay_ms(1);
CS_ON;
time_delay_ms(1);
CS_OFF;
}
The delay and clock initialization routines are from the lptmr and mcg libraries provided by Freescale.
Thanks in advance!
Solved! Go to Solution.
I finally solved the problem! I was watching all the SPI signals on the oscilloscope as you suggested, but everything was ok. Then, I decided to look at the reset signal, but it wasn't cleared in the initialization, then I found the error... in line 13 of my code I wrote:
#define ADReset_OFF GPIOA_PCOR = 1<13
I missed one of this characters: <
It should be:
#define ADReset_OFF GPIOA_PCOR = 1 << 13
It's working now. Thanks for your help!
Hi,
Please refer attached KL25 SPI master/slave example code attached.
Wish it helps.
Have a great day,
best regards,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thanks for the code. I have seen the SPI initialization, but I can't find any differences between your attached code and mine (with the exception that I'm using a GPIO as SS).
Any ideas?
Hi,
Could you get any signal output from KL25 SPI port with scope? If the SPI communication signals as expected?
Have a great day,
best regards,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
I finally solved the problem! I was watching all the SPI signals on the oscilloscope as you suggested, but everything was ok. Then, I decided to look at the reset signal, but it wasn't cleared in the initialization, then I found the error... in line 13 of my code I wrote:
#define ADReset_OFF GPIOA_PCOR = 1<13
I missed one of this characters: <
It should be:
#define ADReset_OFF GPIOA_PCOR = 1 << 13
It's working now. Thanks for your help!