11 ARM SPI-DAC MCP4921
GPIO Port Control (GPIOPCTL)
GPIO Port A (APB) base: 0x4000.4000
En la siguiente imagen se presenta como configurar cada pin desde el PCTL para que sea usado como función alternativa. En este caso queremos usar el PA2, PA3 y PA5. Por lo tanto necesitamos configurar los bits 8-11, 12-15 y 20-23 de este registro. De acuerdo con la hoja de datos, el valor que se tiene que colocar en estos nibbles es: 0x02 (ver la siguiente imagen).
Nota para mayor información, consulte la hoja de datos en la pagina 688.
E
GPIO Port A (APB) base: 0x4000.4000
En la siguiente imagen se presenta como configurar cada pin desde el PCTL para que sea usado como función alternativa. En este caso queremos usar el PA2, PA3 y PA5. Por lo tanto necesitamos configurar los bits 8-11, 12-15 y 20-23 de este registro. De acuerdo con la hoja de datos, el valor que se tiene que colocar en estos nibbles es: 0x02 (ver la siguiente imagen).
Nota para mayor información, consulte la hoja de datos en la pagina 688.
E
Codigo
#include "TM4C123.h" // Device header
#define SYSCTL_RIS_R (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R (*((volatile unsigned long *)0x400FE070))
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source 10001111
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL, DIV400
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock, 400/(4+1) = 80MHz
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
__asm void
Delay(unsigned long n)
{
SUBS R0, #1
BNE Delay
bx LR ;//the link register is providing the address to branch to.
}
void spi_init(void){
SYSCTL->RCGCGPIO|=0x1;//Turn on GPIOA
SYSCTL->RCGCSSI|=0x1;//Turn on SSI0
// PA2(SSI0CLK) PA3(SSI0Fss) PA4(SSI0Rx) PA5(SSI0Tx)
GPIOA->DEN|=((0x1<<2)|(0x1<<3)|(0x1<<5));
GPIOA->DIR|=((0x1<<2)|(0x1<<3)|(0x1<<5));
GPIOA->PUR|=((0x1<<2)|(0x1<<3));
GPIOA->PDR|=((0x1<<5));
GPIOA->AFSEL|=((0x1<<2)|(0x1<<3)|(0x1<<5));
GPIOA->PCTL&=~((0xF<<8)|(0xF<<12)|(0xF<<20)); // PA2, PA3 and PA5
GPIOA->PCTL|=((0x2<<8)|(0x2<<12)|(0x2<<20));
//configure for Freescale SPI Format (Single Transfer) with SPO=0 and SPH=0
//For master operations, set the SSICR1 register to 0x0000.0000.
SSI0->CR1=0;//bit 1 SSE: This bit must be cleared before any control registers are reprogrammed.
//Configure the SSI clock source by writing to the SSICC register.
SSI0->CC=(0x0<<0);//3:0 CS SSI Baud Clock Source = 0x0 System clock
//Configure the clock prescale divisor by writing the SSICPSR register
//BR=SysClk/(CPSDVSR * (1 + SCR))
//where CPSDVSR is an even value from 2-254 programmed in the
//SSICPSR register, and SCR is a value from 0-255.
//BR=50MHz/(2*(1+9))=2.5MHz (if SysClk=80MHz then BR=4MHz)
SSI0->CPSR=(0x2<<0);//7:0 CPSDVSR SSI Clock Prescale Divisor = 0x2
SSI0->CR0=0;
SSI0->CR0=((0x9<<8)| //15:8 SCR SSI Serial Clock Rate = 0x9
(0x0<<7)|//7 SPH SSI Serial Clock Phase = 0x0 Data is captured on the first clock edge transition
(0x0<<6)|//6 SPO SSI Serial Clock Polarity = 0x0 A steady state Low value is placed on the SSInClk pin.
(0x0<<4)|//5:4 FRF SSI Frame Format Select = 0x0 Freescale SPI Frame Format
(0xF<<0));//3:0 DSS SSI Data Size Select = 0xF 16-bit data
//Enable the SSI by setting the SSE bit in the SSICR1 register
SSI0->CR1|=(0x1<<1);//1 SSE SSI Synchronous Serial Port Enable = 0x1 SSI operation is enabled
}
void spi_write16(unsigned short data){
//data = (data>>8) & 0x0F;
//data |= 0x30;
SSI0->DR=(data&0xFFFF);
}
void dac_output(unsigned short dac_step){
//send data through spi to dac
spi_write16(((0x7<<12)|(0xFFF&dac_step)));
}
int main()
{
int i;
PLL_Init(); // 80MHz
spi_init();
while(1){
for(i=0;i<=4000;i=i+200){
dac_output(i);
Delay(13333333); // delay ~0.5 sec at 80 MHz
Delay(13333333); // delay ~0.5 sec at 80 MHz
}
}
}
#define SYSCTL_RIS_R (*((volatile unsigned long *)0x400FE050))
#define SYSCTL_RCC_R (*((volatile unsigned long *)0x400FE060))
#define SYSCTL_RCC2_R (*((volatile unsigned long *)0x400FE070))
void PLL_Init(void){
// 0) Use RCC2
SYSCTL_RCC2_R |= 0x80000000; // USERCC2
// 1) bypass PLL while initializing
SYSCTL_RCC2_R |= 0x00000800; // BYPASS2, PLL bypass
// 2) select the crystal value and oscillator source
SYSCTL_RCC_R = (SYSCTL_RCC_R &~0x000007C0) // clear XTAL field, bits 10-6
+ 0x00000540; // 10101, configure for 16 MHz crystal
SYSCTL_RCC2_R &= ~0x00000070; // configure for main oscillator source 10001111
// 3) activate PLL by clearing PWRDN
SYSCTL_RCC2_R &= ~0x00002000;
// 4) set the desired system divider
SYSCTL_RCC2_R |= 0x40000000; // use 400 MHz PLL, DIV400
SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~ 0x1FC00000) // clear system clock divider
+ (4<<22); // configure for 80 MHz clock, 400/(4+1) = 80MHz
// 5) wait for the PLL to lock by polling PLLLRIS
while((SYSCTL_RIS_R&0x00000040)==0){}; // wait for PLLRIS bit
// 6) enable use of PLL by clearing BYPASS
SYSCTL_RCC2_R &= ~0x00000800;
}
__asm void
Delay(unsigned long n)
{
SUBS R0, #1
BNE Delay
bx LR ;//the link register is providing the address to branch to.
}
void spi_init(void){
SYSCTL->RCGCGPIO|=0x1;//Turn on GPIOA
SYSCTL->RCGCSSI|=0x1;//Turn on SSI0
// PA2(SSI0CLK) PA3(SSI0Fss) PA4(SSI0Rx) PA5(SSI0Tx)
GPIOA->DEN|=((0x1<<2)|(0x1<<3)|(0x1<<5));
GPIOA->DIR|=((0x1<<2)|(0x1<<3)|(0x1<<5));
GPIOA->PUR|=((0x1<<2)|(0x1<<3));
GPIOA->PDR|=((0x1<<5));
GPIOA->AFSEL|=((0x1<<2)|(0x1<<3)|(0x1<<5));
GPIOA->PCTL&=~((0xF<<8)|(0xF<<12)|(0xF<<20)); // PA2, PA3 and PA5
GPIOA->PCTL|=((0x2<<8)|(0x2<<12)|(0x2<<20));
//configure for Freescale SPI Format (Single Transfer) with SPO=0 and SPH=0
//For master operations, set the SSICR1 register to 0x0000.0000.
SSI0->CR1=0;//bit 1 SSE: This bit must be cleared before any control registers are reprogrammed.
//Configure the SSI clock source by writing to the SSICC register.
SSI0->CC=(0x0<<0);//3:0 CS SSI Baud Clock Source = 0x0 System clock
//Configure the clock prescale divisor by writing the SSICPSR register
//BR=SysClk/(CPSDVSR * (1 + SCR))
//where CPSDVSR is an even value from 2-254 programmed in the
//SSICPSR register, and SCR is a value from 0-255.
//BR=50MHz/(2*(1+9))=2.5MHz (if SysClk=80MHz then BR=4MHz)
SSI0->CPSR=(0x2<<0);//7:0 CPSDVSR SSI Clock Prescale Divisor = 0x2
SSI0->CR0=0;
SSI0->CR0=((0x9<<8)| //15:8 SCR SSI Serial Clock Rate = 0x9
(0x0<<7)|//7 SPH SSI Serial Clock Phase = 0x0 Data is captured on the first clock edge transition
(0x0<<6)|//6 SPO SSI Serial Clock Polarity = 0x0 A steady state Low value is placed on the SSInClk pin.
(0x0<<4)|//5:4 FRF SSI Frame Format Select = 0x0 Freescale SPI Frame Format
(0xF<<0));//3:0 DSS SSI Data Size Select = 0xF 16-bit data
//Enable the SSI by setting the SSE bit in the SSICR1 register
SSI0->CR1|=(0x1<<1);//1 SSE SSI Synchronous Serial Port Enable = 0x1 SSI operation is enabled
}
void spi_write16(unsigned short data){
//data = (data>>8) & 0x0F;
//data |= 0x30;
SSI0->DR=(data&0xFFFF);
}
void dac_output(unsigned short dac_step){
//send data through spi to dac
spi_write16(((0x7<<12)|(0xFFF&dac_step)));
}
int main()
{
int i;
PLL_Init(); // 80MHz
spi_init();
while(1){
for(i=0;i<=4000;i=i+200){
dac_output(i);
Delay(13333333); // delay ~0.5 sec at 80 MHz
Delay(13333333); // delay ~0.5 sec at 80 MHz
}
}
}
Demostración:
Reto para el estudiante:
Desarrollar una función que permita generar una función seno con una frecuencia de 1kH.
Enviar a [email protected] cuando el codigo funcione correctamente.
Desarrollar una función que permita generar una función seno con una frecuencia de 1kH.
Enviar a [email protected] cuando el codigo funcione correctamente.