本帖最后由 ddllxxrr 于 2015-3-2 21:12 编辑
Arduino Due in Atmel Studio using C (+ Sample Application)
The Arduino Due is a SAM3X8E based microcontroller board. The Atmel SAM3X8E ARM Cortex-M3 CPU is a powerful 32-bit ARM controller running on a 84 MHz clock.
It is very easy to get started using the Arduino software. But i wanted to do something different and program the controller on a register based level using plain C. As a development IDE i am using the Atmel Studio 6 software which has an integrated compiler that generates a basic intel hex or binary file. I am still using the Arduino bootloader and flash tool. You can flash your Arduino Due out of the Atmel Studio software by creating a batch file that is registered as an external tool: mode %1:1200,n,8,1,p
<Arduino Installation Path>\hardware\tools\bossac.exe --port=%1 -U false -e -w -v
Where “Arduino Installation Path” is the location you installed your Arduino software to. In my case it is “C:\Program Files (x86)\Arduino”. You can set up the batch file as an external tool in Arduino Studio with the following configuration:
In the second part of this post i will explain how to create a basic LED blinking application without any additional libraries like ASK or the Arduino Due based one. Your basic microcontroller program is always build in the same way. The upper part of your primary file contains the header includes like #include "sam.h"
In this case, the sam.h file contains information about the SAM3X8E like register addresses and so on. In this application we wont use additional headers. But if you are building a bigger and more complex applications, i strongly advise you to use multiple files. The second thing you will notice is the
int main(void)
function. This function is the entry point of our application. In bigger applications, this function controls the program calling multiple modules and “work” functions. To keep our application running, we will just lock this function by creating an endless loop: while (1)
{
//TODO:: Please write your application code
}
Next we should configure the i/o pins. Those need to be enabled and initialized as outputs to correctly control the on board LED.
The following function initializes the pin 27 of the B-Port (Arduino Dues on board LED) and the pin 0 of the D-Port (Connector Pin 25): static void configure_io(void)
{
// Enable IO
PIOB->PIO_PER = PIO_PB27;
PIOD->PIO_PER = PIO_PD0;
// Set to output
PIOB->PIO_OER = PIO_PB27;
PIOD->PIO_OER = PIO_PD0;
// Disable pull-up
PIOB->PIO_PUDR = PIO_PB27;
PIOD->PIO_PUDR = PIO_PD0;
}
This function also disables the the internal pull-up resistors because we don’t need those four i/o pins configured as outputs.
At this point we can already turn on our LED using following line: PIOB->PIO_SODR = PIO_PB27; To turn the LED off, we can use this command:
PIOB->PIO_CODR = PIO_PB27;
To blink our LED we need some kind of timer. We could use a “sleep” function inside the main loop that just blocks the controller for a given time, but that has a few disadvantages compared to a real timer. One disadvantage is that a “sleep” function does not consider the time needed for your code to be executed. This might lead to irregular execution and is not practical for time based applications.
A timer can be configured by writing data into different registers similar to the i/o pin initialization.
This function initializes our timer to create an interrupt every 2 ms: static void configure_tc(void)
{
// Enable TC0 (27 is TC0)
PMC->PMC_PCER0 = 1 << 27;
// Disable TC clock
TC0->TC_CHANNEL->TC_CCR = TC_CCR_CLKDIS;
// Disable interrupts
TC0->TC_CHANNEL->TC_IDR = 0xFFFFFFFF;
// Clear status register
TC0->TC_CHANNEL->TC_SR;
// Set Mode
TC0->TC_CHANNEL->TC_CMR = TC_CMR_CPCTRG | TC_CMR_TCCLKS_TIMER_CLOCK5;
// Compare Value
TC0->TC_CHANNEL[0].TC_RC = 59; // 24 = 1 ms; 59 = 2 ms
// Configure and enable interrupt on RC compare
NVIC_EnableIRQ((IRQn_Type) ID_TC0);
TC0->TC_CHANNEL->TC_IER = TC_IER_CPCS;
// Reset counter (SWTRG) and enable counter clock (CLKEN)
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
}
At this point the controller generates an interrupt every 2 ms. To capture the interrupt and run code when the interruption occurs we will need following function (interrupt handler):
void TC0_Handler(void)
{
volatile uint32_t ul_status;
// read status from TC0 status register
ul_status = TC0->TC_CHANNEL->TC_SR;
}
You should not rename this function. If you do, your compiler might not know that this is the interrupt handler function for your TC0 (timer 0) interrupt. Inside this function we will read the timer status register but we wont utilize this information as for this application. And that is basically it. You can now combine the i/o pins with the timer handler and make your led blink or measure the timer slices with and oscilloscope. You can find a full example application that toggles the LED and the Arduino Pin 25 every 2 ms below: #include "sam.h"
uint8_t flag;
void TC0_Handler(void)
{
volatile uint32_t ul_status;
// read status from TC0 status register
ul_status = TC0->TC_CHANNEL->TC_SR;
if(flag == 0)
{
// Enable output
PIOB->PIO_SODR = PIO_PB27; // Arduino Due LED (L)
PIOD->PIO_SODR = PIO_PD0; // Arduino Due Pin 25
flag = 1;
}
else
{
// Disable output
PIOB->PIO_CODR = PIO_PB27; // Arduino Due LED (L)
PIOD->PIO_CODR = PIO_PD0; // Arduino Due Pin 25
flag = 0;
}
}
static void configure_tc(void)
{
// Enable TC0 (27 is TC0)
PMC->PMC_PCER0 = 1 << 27;
// Disable TC clock
TC0->TC_CHANNEL->TC_CCR = TC_CCR_CLKDIS;
// Disable interrupts
TC0->TC_CHANNEL->TC_IDR = 0xFFFFFFFF;
// Clear status register
TC0->TC_CHANNEL->TC_SR;
// Set Mode
TC0->TC_CHANNEL->TC_CMR = TC_CMR_CPCTRG | TC_CMR_TCCLKS_TIMER_CLOCK5;
// Compare Value
TC0->TC_CHANNEL[0].TC_RC = 59; // 24 = 1 ms; 59 = 2 ms
// Configure and enable interrupt on RC compare
NVIC_EnableIRQ((IRQn_Type) ID_TC0);
TC0->TC_CHANNEL->TC_IER = TC_IER_CPCS;
// Reset counter (SWTRG) and enable counter clock (CLKEN)
TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
}
static void configure_io(void)
{
// Enable IO
PIOB->PIO_PER = PIO_PB27;
PIOD->PIO_PER = PIO_PD0;
// Set to output
PIOB->PIO_OER = PIO_PB27;
PIOD->PIO_OER = PIO_PD0;
// Disable pull-up
PIOB->PIO_PUDR = PIO_PB27;
PIOD->PIO_PUDR = PIO_PD0;
}
int main(void)
{
/* Initialize the SAM system */
SystemInit();
configure_io();
configure_tc();
flag = 0;
while (1)
{
//TODO:: Please write your application code
}
}
You probably will not be able to see the LED blink because the frequency of 250 Hz is to fast for the human eye to see. You could modify line 48 to increase the interruption interval: TC0->TC_CHANNEL[0].TC_RC = 1000;
If you hook up an oscilloscope to the Arduino Due Pin 25 you will be able to measure the 2 ms slices (Notice thedt of 2.000ms).
|