Incluso si no desea utilizar ASF (ni siquiera uso Atmel Studio), lo mejor es incluir y compilar con Paquetes Atmel que definen todos los registros y pines, de forma similar a los archivos" io.h "utilizados con AVR. Todo el código de ejemplo aquí está usando definiciones / estructuras del paquete SAMD21 . ARM es significativamente diferente a AVR y requiere muchos más pasos para comenzar algo, pero una vez que se cuidan los relojes, es similar a muchos otros microcontroladores en los que solo está configurando valores de registro.
Aquí está la hoja de datos de samd21 , para referencia.
Hay numerosos pasos involucrados, y puedo agregar más detalles a cada uno a solicitud.
1. Configurar los relojes del sistema
Esto es extremadamente complicado, pero es necesario hacer cualquier cosa ...
2. Habilite la alimentación en los módulos (no todos estos son necesarios, solo un ejemplo)
PM->APBBMASK.reg =
PM_APBBMASK_DMAC |
PM_APBBMASK_PORT |
PM_APBBMASK_NVMCTRL;
PM->APBCMASK.reg =
PM_APBCMASK_ADC | // This is for the ADC
PM_APBCMASK_DAC | // This is for the DAC
PM_APBCMASK_TC3; // This is for Timer/Counter 3
3. Configurar puertos y pines
DAC para SAMD21 es PA02, puerto MUX B
4. Conecte el reloj genérico al módulo
#define DAC_GCLKGEN 3 // examples using GLCK Generator 3
GCLK->CLKCTRL.reg = (DAC_GCLKGEN << 8) | GCLK_CLKCTRL_ID_DAC | GCLK_CLKCTRL_CLKEN;
while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
5. Configure los registros del módulo
DAC->CTRLB.reg = 0x40; // use AVCC as the reference
6. Crea algunas macros / funciones
#define DAC_VREF 3.3f // this is the value of AVCC, the reference voltage
#define DAC_MASK 0x3FF // DAC is 12 bit, so this is the maximum value
#define DAC_FACTOR (DAC_MASK / DAC_VREF) // For converting to voltage
#define DAC_ON() DAC->CTRLB.reg = 0x43
#define DAC_OFF() DAC->CTRLB.reg = 0x40
/**
* Set the DAC output register with the value.
*
* @param value 12-bit value to be set
*/
static void
DAC_setRaw(const uint16_t value) {
DAC_OFF();
DAC->CTRLA.reg = DAC_CTRLA_ENABLE;
while (1 == DAC->STATUS.bit.SYNCBUSY);
DAC->DATA.reg = DAC_MASK & value;
while (1 == DAC->STATUS.bit.SYNCBUSY);
DAC_ON();
}
/**
* Set the DAC output register with the value.
* @note the 8-bit value is left shifted; the 4 lsb are 0.
*
* @param value 8-bit value to be set
*/
static inline void
DAC_setRaw8(const uint8_t value) {
DAC_setRaw((uint16_t)(value) << 4);
}
/**
* Set the DAC to be the specified potential.
*
* @param potential the potential to be set
*/
static inline void
DAC_set(const float potential) {
DAC_setRaw((uint16_t)(potential * DAC_FACTOR);
}
7. Usa las funciones en tu código
No sé cuáles son sus "entradas" en realidad o de dónde provienen, pero puede usar las funciones DAC_setRaw () y DAC_setRaw8 () para configurar usando un número sin formato o la función DAC_set () para establecer usando un número de punto flotante de voltaje.
También hay una entrada de ADC conectada internamente al DAC que puede usar para verificar si realmente se está ejecutando, pero eso es una historia para otro día ...