blob: bd7ec2d8f534ad217afd0095f4f56e2cd785fa51 [file] [log] [blame]
/*
Copyright (c) 2011 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Arduino.h"
#ifdef __cplusplus
extern "C" {
#endif
eAnalogReference analog_reference = AR_DEFAULT;
void analogReference(eAnalogReference ulMode)
{
analog_reference = ulMode;
}
uint32_t analogRead(uint32_t ulPin)
{
uint32_t ulValue = 0;
uint32_t ulChannel;
if (ulPin < A0)
ulPin += A0;
ulChannel = g_APinDescription[ulPin].ulADCChannelNumber ;
#if defined __SAM3U4E__
switch ( g_APinDescription[ulPin].ulAnalogChannel )
{
// Handling ADC 10 bits channels
case ADC0 :
case ADC1 :
case ADC2 :
case ADC3 :
case ADC4 :
case ADC5 :
case ADC6 :
case ADC7 :
// Enable the corresponding channel
adc_enable_channel( ADC, ulChannel );
// Start the ADC
adc_start( ADC );
// Wait for end of conversion
while ((adc_get_status(ADC) & ADC_SR_DRDY) != ADC_SR_DRDY)
;
// Read the value
ulValue = adc_get_latest_value(ADC);
// Disable the corresponding channel
adc_disable_channel( ADC, ulChannel );
// Stop the ADC
// adc_stop( ADC ) ; // never do adc_stop() else we have to reconfigure the ADC each time
break;
// Handling ADC 12 bits channels
case ADC8 :
case ADC9 :
case ADC10 :
case ADC11 :
case ADC12 :
case ADC13 :
case ADC14 :
case ADC15 :
// Enable the corresponding channel
adc12b_enable_channel( ADC12B, ulChannel );
// Start the ADC12B
adc12b_start( ADC12B );
// Wait for end of conversion
while ((adc12b_get_status(ADC12B) & ADC12B_SR_DRDY) != ADC12B_SR_DRDY)
;
// Read the value
ulValue = adc12b_get_latest_value(ADC12B);
// Stop the ADC12B
// adc12_stop( ADC12B ) ; // never do adc12_stop() else we have to reconfigure the ADC12B each time
// Disable the corresponding channel
adc12b_disable_channel( ADC12B, ulChannel );
break;
// Compiler could yell because we don't handle DAC pins
default :
ulValue=0;
break;
}
#endif
#if defined __SAM3X8E__ || defined __SAM3X8H__
switch ( g_APinDescription[ulPin].ulAnalogChannel )
{
// Handling ADC 10 bits channels
case ADC0 :
case ADC1 :
case ADC2 :
case ADC3 :
case ADC4 :
case ADC5 :
case ADC6 :
case ADC7 :
case ADC8 :
case ADC9 :
case ADC10 :
case ADC11 :
// Enable the corresponding channel
adc_enable_channel( ADC, ulChannel );
// Start the ADC
adc_start( ADC );
// Wait for end of conversion
while ((adc_get_status(ADC) & ADC_ISR_DRDY) != ADC_ISR_DRDY)
;
// Read the value
ulValue = adc_get_latest_value(ADC);
// Disable the corresponding channel
adc_disable_channel(ADC, ulChannel);
break;
// Compiler could yell because we don't handle DAC pins
default :
ulValue=0;
break;
}
#endif
return ulValue;
}
static void TC_SetRA(Tc *tc, uint32_t chan, uint32_t v )
{
tc->TC_CHANNEL[chan].TC_RA = v;
}
static void TC_SetRB(Tc *tc, uint32_t chan, uint32_t v )
{
tc->TC_CHANNEL[chan].TC_RB = v;
}
static void TC_SetRC(Tc *tc, uint32_t chan, uint32_t v )
{
tc->TC_CHANNEL[chan].TC_RC = v;
}
static uint8_t PWMEnabled = 0;
static uint8_t pinEnabled[PINS_COUNT];
static uint8_t TCChanEnabled[] = {0, 0, 0};
void analogOutputInit(void) {
uint8_t i;
for (i=0; i<PINS_COUNT; i++)
pinEnabled[i] = 0;
}
// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// pins_*.c file. For the rest of the pins, we default
// to digital output.
void analogWrite(uint32_t ulPin, uint32_t ulValue) {
uint32_t attr = g_APinDescription[ulPin].ulPinAttribute;
if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM) {
if (!PWMEnabled) {
// PWM Startup code
pmc_enable_periph_clk(PWM_INTERFACE_ID);
PWMC_ConfigureClocks(PWM_FREQUENCY * PWM_MAX_DUTY_CYCLE, 0, VARIANT_MCK);
PWMEnabled = 1;
}
uint32_t chan = g_APinDescription[ulPin].ulPWMChannel;
if (!pinEnabled[ulPin]) {
// Setup PWM for this pin
PIO_Configure(g_APinDescription[ulPin].pPort,
g_APinDescription[ulPin].ulPinType,
g_APinDescription[ulPin].ulPin,
g_APinDescription[ulPin].ulPinConfiguration);
PWMC_ConfigureChannel(PWM_INTERFACE, chan, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_SetPeriod(PWM_INTERFACE, chan, PWM_MAX_DUTY_CYCLE);
PWMC_SetDutyCycle(PWM_INTERFACE, chan, ulValue);
PWMC_EnableChannel(PWM_INTERFACE, chan);
pinEnabled[ulPin] = 1;
}
PWMC_SetDutyCycle(PWM_INTERFACE, chan, ulValue);
return;
}
if ((attr & PIN_ATTR_TIMER) == PIN_ATTR_TIMER) {
// We use MCLK/2 => 96Mhz/2 => 48Mhz as clock.
// To get 1KHz we should use 48000 as TC
// 48Mhz/48000 = 1KHz
const uint32_t TC = VARIANT_MCK / 2 / TC_FREQUENCY;
// Map value to Timer ranges 0..255=>0..48000
ulValue = ulValue * TC;
ulValue = ulValue / TC_MAX_DUTY_CYCLE;
// Setup Timer for this pin
ETCChannel channel = g_APinDescription[ulPin].ulTCChannel;
static const uint32_t channelToChNo[] = { 0, 0, 1, 1, 2, 2 };
static const uint32_t channelToAB[] = { 1, 0, 1, 0, 1, 0 };
uint32_t chNo = channelToChNo[channel];
uint32_t chA = channelToAB[channel];
if (!TCChanEnabled[chNo]) {
pmc_enable_periph_clk(TC_INTERFACE_ID + chNo);
TC_Configure(TC_INTERFACE, chNo,
TC_CMR_TCCLKS_TIMER_CLOCK1 |
TC_CMR_WAVE |
TC_CMR_WAVSEL_UP_RC |
TC_CMR_ACPA_CLEAR | // RA Compare Effect on OA: clear
TC_CMR_ACPC_SET | // RC Compare Effect on OA: set
TC_CMR_BCPB_CLEAR | // RB Compare Effect on OB: clear
TC_CMR_BCPC_SET); // RC Compare Effect on OB: set
TC_SetRC(TC_INTERFACE, chNo, TC);
}
if (chA)
TC_SetRA(TC_INTERFACE, chNo, ulValue);
else
TC_SetRB(TC_INTERFACE, chNo, ulValue);
if (!pinEnabled[ulPin]) {
PIO_Configure(g_APinDescription[ulPin].pPort,
g_APinDescription[ulPin].ulPinType,
g_APinDescription[ulPin].ulPin,
g_APinDescription[ulPin].ulPinConfiguration);
pinEnabled[ulPin] = 1;
}
if (!TCChanEnabled[chNo]) {
TC_Start(TC_INTERFACE, chNo);
TCChanEnabled[chNo] = 1;
}
return;
}
// Default to digital write
pinMode(ulPin, OUTPUT);
if (ulValue < 128)
digitalWrite(ulPin, LOW);
else
digitalWrite(ulPin, HIGH);
}
#ifdef __cplusplus
}
#endif