src folder

This commit is contained in:
Malte Reents 2024-05-19 11:42:35 +02:00
parent 7930813118
commit dec8a3f3f8
622 changed files with 95058 additions and 0 deletions

172
src/HAL/AVR/HAL.cpp Normal file
View File

@ -0,0 +1,172 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
#include <avr/wdt.h>
#ifdef USBCON
DefaultSerial1 MSerial0(false, Serial);
#ifdef BLUETOOTH
BTSerial btSerial(false, bluetoothSerial);
#endif
#endif
// ------------------------
// Public Variables
// ------------------------
// Don't initialize/override variable (which would happen in .init4)
uint8_t MarlinHAL::reset_reason __attribute__((section(".noinit")));
// ------------------------
// Public functions
// ------------------------
__attribute__((naked)) // Don't output function pro- and epilogue
__attribute__((used)) // Output the function, even if "not used"
__attribute__((section(".init3"))) // Put in an early user definable section
void save_reset_reason() {
#if ENABLED(OPTIBOOT_RESET_REASON)
__asm__ __volatile__(
A("STS %0, r2")
: "=m"(hal.reset_reason)
);
#else
hal.reset_reason = MCUSR;
#endif
// Clear within 16ms since WDRF bit enables a 16ms watchdog timer -> Boot loop
hal.clear_reset_source();
wdt_disable();
}
void MarlinHAL::init() {
// Init Servo Pins
#define INIT_SERVO(N) OUT_WRITE(SERVO##N##_PIN, LOW)
#if HAS_SERVO_0
INIT_SERVO(0);
#endif
#if HAS_SERVO_1
INIT_SERVO(1);
#endif
#if HAS_SERVO_2
INIT_SERVO(2);
#endif
#if HAS_SERVO_3
INIT_SERVO(3);
#endif
init_pwm_timers(); // Init user timers to default frequency - 1000HZ
}
void MarlinHAL::reboot() {
#if ENABLED(USE_WATCHDOG)
while (1) { /* run out the watchdog */ }
#else
void (*resetFunc)() = 0; // Declare resetFunc() at address 0
resetFunc(); // Jump to address 0
#endif
}
// ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
#include <avr/wdt.h>
#include "../../MarlinCore.h"
// Initialize watchdog with 8s timeout, if possible. Otherwise, make it 4s.
void MarlinHAL::watchdog_init() {
#if ENABLED(WATCHDOG_DURATION_8S) && defined(WDTO_8S)
#define WDTO_NS WDTO_8S
#else
#define WDTO_NS WDTO_4S
#endif
#if ENABLED(WATCHDOG_RESET_MANUAL)
// Enable the watchdog timer, but only for the interrupt.
// Take care, as this requires the correct order of operation, with interrupts disabled.
// See the datasheet of any AVR chip for details.
wdt_reset();
cli();
_WD_CONTROL_REG = _BV(_WD_CHANGE_BIT) | _BV(WDE);
_WD_CONTROL_REG = _BV(WDIE) | (WDTO_NS & 0x07) | ((WDTO_NS & 0x08) << 2); // WDTO_NS directly does not work. bit 0-2 are consecutive in the register but the highest value bit is at bit 5
// So worked for up to WDTO_2S
sei();
wdt_reset();
#else
wdt_enable(WDTO_NS); // The function handles the upper bit correct.
#endif
//delay(10000); // test it!
}
//===========================================================================
//=================================== ISR ===================================
//===========================================================================
// Watchdog timer interrupt, called if main program blocks >4sec and manual reset is enabled.
#if ENABLED(WATCHDOG_RESET_MANUAL)
ISR(WDT_vect) {
sei(); // With the interrupt driven serial we need to allow interrupts.
SERIAL_ERROR_MSG(STR_WATCHDOG_FIRED);
minkill(); // interrupt-safe final kill and infinite loop
}
#endif
// Reset watchdog. MUST be called at least every 4 seconds after the
// first watchdog_init or AVR will go into emergency procedures.
void MarlinHAL::watchdog_refresh() { wdt_reset(); }
#endif // USE_WATCHDOG
// ------------------------
// Free Memory Accessor
// ------------------------
#if ENABLED(SDSUPPORT)
#include "../../sd/SdFatUtil.h"
int freeMemory() { return SdFatUtil::FreeRam(); }
#else // !SDSUPPORT
extern "C" {
extern char __bss_end;
extern char __heap_start;
extern void* __brkval;
int freeMemory() {
int free_memory;
if ((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
}
#endif // !SDSUPPORT
#endif // __AVR__

277
src/HAL/AVR/HAL.h Normal file
View File

@ -0,0 +1,277 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* HAL for Arduino AVR
*/
#include "../shared/Marduino.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include "math.h"
#ifdef USBCON
#include <HardwareSerial.h>
#else
#include "MarlinSerial.h"
#endif
#include <stdint.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/io.h>
//
// Default graphical display delays
//
#if F_CPU >= 20000000
#define CPU_ST7920_DELAY_1 150
#define CPU_ST7920_DELAY_2 0
#define CPU_ST7920_DELAY_3 150
#elif F_CPU == 16000000
#define CPU_ST7920_DELAY_1 125
#define CPU_ST7920_DELAY_2 0
#define CPU_ST7920_DELAY_3 188
#endif
#ifndef pgm_read_ptr
// Compatibility for avr-libc 1.8.0-4.1 included with Ubuntu for
// Windows Subsystem for Linux on Windows 10 as of 10/18/2019
#define pgm_read_ptr_far(address_long) (void*)__ELPM_word((uint32_t)(address_long))
#define pgm_read_ptr_near(address_short) (void*)__LPM_word((uint16_t)(address_short))
#define pgm_read_ptr(address_short) pgm_read_ptr_near(address_short)
#endif
// ------------------------
// Defines
// ------------------------
// AVR PROGMEM extension for sprintf_P
#define S_FMT "%S"
// AVR PROGMEM extension for string define
#define PGMSTR(NAM,STR) const char NAM[] PROGMEM = STR
#ifndef CRITICAL_SECTION_START
#define CRITICAL_SECTION_START() unsigned char _sreg = SREG; cli()
#define CRITICAL_SECTION_END() SREG = _sreg
#endif
#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
#define PWM_FREQUENCY 1000 // Default PWM frequency when set_pwm_duty() is called without set_pwm_frequency()
// ------------------------
// Types
// ------------------------
typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp
class Servo;
typedef Servo hal_servo_t;
// ------------------------
// Serial ports
// ------------------------
#ifdef USBCON
#include "../../core/serial_hook.h"
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
extern DefaultSerial1 MSerial0;
#ifdef BLUETOOTH
typedef ForwardSerial1Class< decltype(bluetoothSerial) > BTSerial;
extern BTSerial btSerial;
#endif
#define MYSERIAL1 TERN(BLUETOOTH, btSerial, MSerial0)
#else
#if !WITHIN(SERIAL_PORT, -1, 3)
#error "SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif
#define MYSERIAL1 customizedSerial1
#ifdef SERIAL_PORT_2
#if !WITHIN(SERIAL_PORT_2, -1, 3)
#error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial."
#endif
#define MYSERIAL2 customizedSerial2
#endif
#ifdef SERIAL_PORT_3
#if !WITHIN(SERIAL_PORT_3, -1, 3)
#error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial."
#endif
#define MYSERIAL3 customizedSerial3
#endif
#endif
#ifdef MMU2_SERIAL_PORT
#if !WITHIN(MMU2_SERIAL_PORT, -1, 3)
#error "MMU2_SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif
#define MMU2_SERIAL mmuSerial
#endif
#ifdef LCD_SERIAL_PORT
#if !WITHIN(LCD_SERIAL_PORT, -1, 3)
#error "LCD_SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif
#define LCD_SERIAL lcdSerial
#if HAS_DGUS_LCD
#define SERIAL_GET_TX_BUFFER_FREE() LCD_SERIAL.get_tx_buffer_free()
#endif
#endif
//
// ADC
//
#define HAL_ADC_VREF 5.0
#define HAL_ADC_RESOLUTION 10
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
#define HAL_SENSITIVE_PINS 0, 1,
#ifdef __AVR_AT90USB1286__
#define JTAG_DISABLE() do{ MCUCR = 0x80; MCUCR = 0x80; }while(0)
#endif
// AVR compatibility
#define strtof strtod
// ------------------------
// Free Memory Accessor
// ------------------------
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
extern "C" int freeMemory();
#pragma GCC diagnostic pop
// ------------------------
// MarlinHAL Class
// ------------------------
class MarlinHAL {
public:
// Earliest possible init, before setup()
MarlinHAL() {}
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});
static void init(); // Called early in setup()
static void init_board() {} // Called less early in setup()
static void reboot(); // Restart the firmware from 0x0
// Interrupts
static bool isr_state() { return TEST(SREG, SREG_I); }
static void isr_on() { sei(); }
static void isr_off() { cli(); }
static void delay_ms(const int ms) { _delay_ms(ms); }
// Tasks, called from idle()
static void idletask() {}
// Reset
static uint8_t reset_reason;
static uint8_t get_reset_source() { return reset_reason; }
static void clear_reset_source() { MCUSR = 0; }
// Free SRAM
static int freeMemory() { return ::freeMemory(); }
//
// ADC Methods
//
// Called by Temperature::init once at startup
static void adc_init() {
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADIF) | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
}
// Called by Temperature::init for each sensor at startup
static void adc_enable(const uint8_t ch) {
#ifdef DIDR2
if (ch > 7) { SBI(DIDR2, ch & 0x07); return; }
#endif
SBI(DIDR0, ch);
}
// Begin ADC sampling on the given channel. Called from Temperature::isr!
static void adc_start(const uint8_t ch) {
#ifdef MUX5
ADCSRB = ch > 7 ? _BV(MUX5) : 0;
#else
ADCSRB = 0;
#endif
ADMUX = _BV(REFS0) | (ch & 0x07);
SBI(ADCSRA, ADSC);
}
// Is the ADC ready for reading?
static bool adc_ready() { return !TEST(ADCSRA, ADSC); }
// The current value of the ADC register
static __typeof__(ADC) adc_value() { return ADC; }
/**
* init_pwm_timers
* Set the default frequency for timers 2-5 to 1000HZ
*/
static void init_pwm_timers();
/**
* Set the PWM duty cycle for the pin to the given value.
* Optionally invert the duty cycle [default = false]
* Optionally change the scale of the provided value to enable finer PWM duty control [default = 255]
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
/**
* Set the frequency of the timer for the given pin as close as
* possible to the provided desired frequency. Internally calculate
* the required waveform generation mode, prescaler, and resolution
* values and set timer registers accordingly.
* NOTE that the frequency is applied to all pins on the timer (Ex OC3A, OC3B and OC3B)
* NOTE that there are limitations, particularly if using TIMER2. (see Configuration_adv.h -> FAST_PWM_FAN Settings)
*/
static void set_pwm_frequency(const pin_t pin, const uint16_t f_desired);
};

254
src/HAL/AVR/HAL_SPI.cpp Normal file
View File

@ -0,0 +1,254 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Adapted from Arduino Sd2Card Library
* Copyright (c) 2009 by William Greiman
*/
/**
* HAL for AVR - SPI functions
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
void spiBegin() {
#if PIN_EXISTS(SD_SS)
// Do not init HIGH for boards with pin 4 used as Fans or Heaters or otherwise, not likely to have multiple SPI devices anyway.
#if defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
// SS must be in output mode even it is not chip select
SET_OUTPUT(SD_SS_PIN);
#else
// set SS high - may be chip select for another SPI device
OUT_WRITE(SD_SS_PIN, HIGH);
#endif
#endif
SET_OUTPUT(SD_SCK_PIN);
SET_INPUT(SD_MISO_PIN);
SET_OUTPUT(SD_MOSI_PIN);
IF_DISABLED(SOFTWARE_SPI, spiInit(SPI_HALF_SPEED));
}
#if NONE(SOFTWARE_SPI, FORCE_SOFT_SPI)
// ------------------------
// Hardware SPI
// ------------------------
// make sure SPCR rate is in expected bits
#if (SPR0 != 0 || SPR1 != 1)
#error "unexpected SPCR bits"
#endif
/**
* Initialize hardware SPI
* Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
*/
void spiInit(uint8_t spiRate) {
// See avr processor documentation
CBI(
#ifdef PRR
PRR
#elif defined(PRR0)
PRR0
#endif
, PRSPI
);
SPCR = _BV(SPE) | _BV(MSTR) | (spiRate >> 1);
SPSR = spiRate & 1 || spiRate == 6 ? 0 : _BV(SPI2X);
}
/** SPI receive a byte */
uint8_t spiRec() {
SPDR = 0xFF;
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
return SPDR;
}
/** SPI read data */
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte-- == 0) return;
SPDR = 0xFF;
for (uint16_t i = 0; i < nbyte; i++) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
buf[i] = SPDR;
SPDR = 0xFF;
}
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
buf[nbyte] = SPDR;
}
/** SPI send a byte */
void spiSend(uint8_t b) {
SPDR = b;
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
}
/** SPI send block */
void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) {
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
SPDR = buf[i];
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
SPDR = buf[i + 1];
}
while (!TEST(SPSR, SPIF)) { /* Intentionally left empty */ }
}
/** begin spi transaction */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
// Based on Arduino SPI library
// Clock settings are defined as follows. Note that this shows SPI2X
// inverted, so the bits form increasing numbers. Also note that
// fosc/64 appears twice
// SPR1 SPR0 ~SPI2X Freq
// 0 0 0 fosc/2
// 0 0 1 fosc/4
// 0 1 0 fosc/8
// 0 1 1 fosc/16
// 1 0 0 fosc/32
// 1 0 1 fosc/64
// 1 1 0 fosc/64
// 1 1 1 fosc/128
// We find the fastest clock that is less than or equal to the
// given clock rate. The clock divider that results in clock_setting
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
// slowest (128 == 2 ^^ 7, so clock_div = 6).
uint8_t clockDiv;
// When the clock is known at compiletime, use this if-then-else
// cascade, which the compiler knows how to completely optimize
// away. When clock is not known, use a loop instead, which generates
// shorter code.
if (__builtin_constant_p(spiClock)) {
if (spiClock >= F_CPU / 2) clockDiv = 0;
else if (spiClock >= F_CPU / 4) clockDiv = 1;
else if (spiClock >= F_CPU / 8) clockDiv = 2;
else if (spiClock >= F_CPU / 16) clockDiv = 3;
else if (spiClock >= F_CPU / 32) clockDiv = 4;
else if (spiClock >= F_CPU / 64) clockDiv = 5;
else clockDiv = 6;
}
else {
uint32_t clockSetting = F_CPU / 2;
clockDiv = 0;
while (clockDiv < 6 && spiClock < clockSetting) {
clockSetting /= 2;
clockDiv++;
}
}
// Compensate for the duplicate fosc/64
if (clockDiv == 6) clockDiv = 7;
// Invert the SPI2X bit
clockDiv ^= 0x1;
SPCR = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
(dataMode << CPHA) | ((clockDiv >> 1) << SPR0);
SPSR = clockDiv | 0x01;
}
#else // SOFTWARE_SPI || FORCE_SOFT_SPI
// ------------------------
// Software SPI
// ------------------------
// nop to tune soft SPI timing
#define nop asm volatile ("\tnop\n")
void spiInit(uint8_t) { /* do nothing */ }
// Begin SPI transaction, set clock, bit order, data mode
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) { /* do nothing */ }
// Soft SPI receive byte
uint8_t spiRec() {
uint8_t data = 0;
// no interrupts during byte receive - about 8µs
cli();
// output pin high - like sending 0xFF
WRITE(SD_MOSI_PIN, HIGH);
LOOP_L_N(i, 8) {
WRITE(SD_SCK_PIN, HIGH);
nop; // adjust so SCK is nice
nop;
data <<= 1;
if (READ(SD_MISO_PIN)) data |= 1;
WRITE(SD_SCK_PIN, LOW);
}
sei();
return data;
}
// Soft SPI read data
void spiRead(uint8_t *buf, uint16_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++)
buf[i] = spiRec();
}
// Soft SPI send byte
void spiSend(uint8_t data) {
// no interrupts during byte send - about 8µs
cli();
LOOP_L_N(i, 8) {
WRITE(SD_SCK_PIN, LOW);
WRITE(SD_MOSI_PIN, data & 0x80);
data <<= 1;
WRITE(SD_SCK_PIN, HIGH);
}
nop; // hold SCK high for a few ns
nop;
nop;
nop;
WRITE(SD_SCK_PIN, LOW);
sei();
}
// Soft SPI send block
void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiSend(token);
for (uint16_t i = 0; i < 512; i++)
spiSend(buf[i]);
}
#endif // SOFTWARE_SPI || FORCE_SOFT_SPI
#endif // __AVR__

26
src/HAL/AVR/MarlinSPI.h Normal file
View File

@ -0,0 +1,26 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <SPI.h>
using MarlinSPI = SPIClass;

View File

@ -0,0 +1,652 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* MarlinSerial.cpp - Hardware serial library for Wiring
* Copyright (c) 2006 Nicholas Zambetti. All right reserved.
*
* Modified 23 November 2006 by David A. Mellis
* Modified 28 September 2010 by Mark Sproul
* Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
* Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
* Modified 10 June 2018 by Eduardo José Tagle (See #10991)
* Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances
*/
#ifdef __AVR__
// Disable HardwareSerial.cpp to support chips without a UART (Attiny, etc.)
#include "../../inc/MarlinConfig.h"
#if !defined(USBCON) && (defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H))
#include "MarlinSerial.h"
#include "../../MarlinCore.h"
#if ENABLED(DIRECT_STEPPING)
#include "../../feature/direct_stepping.h"
#endif
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0, 0, { 0 } };
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
template<typename Cfg> bool MarlinSerial<Cfg>::_written = false;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::xon_xoff_state = MarlinSerial<Cfg>::XON_XOFF_CHAR_SENT | MarlinSerial<Cfg>::XON_CHAR;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_dropped_bytes = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_buffer_overruns = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_framing_errors = 0;
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::rx_max_enqueued = 0;
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
#include "../../feature/e_parser.h"
// "Atomically" read the RX head index value without disabling interrupts:
// This MUST be called with RX interrupts enabled, and CAN'T be called
// from the RX ISR itself!
template<typename Cfg>
FORCE_INLINE typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::atomic_read_rx_head() {
if (Cfg::RX_SIZE > 256) {
// Keep reading until 2 consecutive reads return the same value,
// meaning there was no update in-between caused by an interrupt.
// This works because serial RX interrupts happen at a slower rate
// than successive reads of a variable, so 2 consecutive reads with
// the same value means no interrupt updated it.
ring_buffer_pos_t vold, vnew = rx_buffer.head;
sw_barrier();
do {
vold = vnew;
vnew = rx_buffer.head;
sw_barrier();
} while (vold != vnew);
return vnew;
}
else {
// With an 8bit index, reads are always atomic. No need for special handling
return rx_buffer.head;
}
}
template<typename Cfg>
volatile bool MarlinSerial<Cfg>::rx_tail_value_not_stable = false;
template<typename Cfg>
volatile uint16_t MarlinSerial<Cfg>::rx_tail_value_backup = 0;
// Set RX tail index, taking into account the RX ISR could interrupt
// the write to this variable in the middle - So a backup strategy
// is used to ensure reads of the correct values.
// -Must NOT be called from the RX ISR -
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::atomic_set_rx_tail(typename MarlinSerial<Cfg>::ring_buffer_pos_t value) {
if (Cfg::RX_SIZE > 256) {
// Store the new value in the backup
rx_tail_value_backup = value;
sw_barrier();
// Flag we are about to change the true value
rx_tail_value_not_stable = true;
sw_barrier();
// Store the new value
rx_buffer.tail = value;
sw_barrier();
// Signal the new value is completely stored into the value
rx_tail_value_not_stable = false;
sw_barrier();
}
else
rx_buffer.tail = value;
}
// Get the RX tail index, taking into account the read could be
// interrupting in the middle of the update of that index value
// -Called from the RX ISR -
template<typename Cfg>
FORCE_INLINE typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::atomic_read_rx_tail() {
if (Cfg::RX_SIZE > 256) {
// If the true index is being modified, return the backup value
if (rx_tail_value_not_stable) return rx_tail_value_backup;
}
// The true index is stable, return it
return rx_buffer.tail;
}
// (called with RX interrupts disabled)
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::store_rxd_char() {
static EmergencyParser::State emergency_state; // = EP_RESET
// This must read the R_UCSRA register before reading the received byte to detect error causes
if (Cfg::DROPPED_RX && B_DOR && !++rx_dropped_bytes) --rx_dropped_bytes;
if (Cfg::RX_OVERRUNS && B_DOR && !++rx_buffer_overruns) --rx_buffer_overruns;
if (Cfg::RX_FRAMING_ERRORS && B_FE && !++rx_framing_errors) --rx_framing_errors;
// Read the character from the USART
uint8_t c = R_UDR;
#if ENABLED(DIRECT_STEPPING)
if (page_manager.maybe_store_rxd_char(c)) return;
#endif
// Get the tail - Nothing can alter its value while this ISR is executing, but there's
// a chance that this ISR interrupted the main process while it was updating the index.
// The backup mechanism ensures the correct value is always returned.
const ring_buffer_pos_t t = atomic_read_rx_tail();
// Get the head pointer - This ISR is the only one that modifies its value, so it's safe to read here
ring_buffer_pos_t h = rx_buffer.head;
// Get the next element
ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the RX FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
if (Cfg::MAX_RX_QUEUED) {
// Calculate count of bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Keep track of the maximum count of enqueued bytes
NOLESS(rx_max_enqueued, rx_count);
}
if (Cfg::XONOFF) {
// If the last char that was sent was an XON
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
// Bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// If over 12.5% of RX buffer capacity, send XOFF before running out of
// RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
// and stop sending bytes. This translates to 13mS propagation time.
if (rx_count >= (Cfg::RX_SIZE) / 8) {
// At this point, definitely no TX interrupt was executing, since the TX ISR can't be preempted.
// Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
// to be in the middle of trying to disable the RX interrupt in the main program, eventually the
// enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
// the sending of the XOFF char is to send it HERE AND NOW.
// About to send the XOFF char
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
// Wait until the TX register becomes empty and send it - Here there could be a problem
// - While waiting for the TX register to empty, the RX register could receive a new
// character. This must also handle that situation!
while (!B_UDRE) {
if (B_RXC) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = R_UDR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
R_UDR = XOFF_CHAR;
// Clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
// At this point there could be a race condition between the write() function
// and this sending of the XOFF char. This interrupt could happen between the
// wait to be empty TX buffer loop and the actual write of the character. Since
// the TX buffer is full because it's sending the XOFF char, the only way to be
// sure the write() function will succeed is to wait for the XOFF char to be
// completely sent. Since an extra character could be received during the wait
// it must also be handled!
while (!B_UDRE) {
if (B_RXC) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = R_UDR;
if (Cfg::EMERGENCYPARSER)
emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
// At this point everything is ready. The write() function won't
// have any issues writing to the UART TX register if it needs to!
}
}
}
// Store the new head value - The main loop will retry until the value is stable
rx_buffer.head = h;
}
// (called with TX irqs disabled)
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::_tx_udr_empty_irq() {
if (Cfg::TX_SIZE > 0) {
// Read positions
uint8_t t = tx_buffer.tail;
const uint8_t h = tx_buffer.head;
if (Cfg::XONOFF) {
// If an XON char is pending to be sent, do it now
if (xon_xoff_state == XON_CHAR) {
// Send the character
R_UDR = XON_CHAR;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
// Remember we sent it.
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
// If nothing else to transmit, just disable TX interrupts.
if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
return;
}
}
// If nothing to transmit, just disable TX interrupts. This could
// happen as the result of the non atomicity of the disabling of RX
// interrupts that could end reenabling TX interrupts as a side effect.
if (h == t) {
B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
return;
}
// There is something to TX, Send the next byte
const uint8_t c = tx_buffer.buffer[t];
t = (t + 1) & (Cfg::TX_SIZE - 1);
R_UDR = c;
tx_buffer.tail = t;
// Clear the TXC bit (by writing a one to its bit location).
// Ensures flush() won't return until the bytes are actually written/
B_TXC = 1;
// Disable interrupts if there is nothing to transmit following this byte
if (h == t) B_UDRIE = 0; // (Non-atomic, could be reenabled by the main program, but eventually this will succeed)
}
}
// Public Methods
template<typename Cfg>
void MarlinSerial<Cfg>::begin(const long baud) {
uint16_t baud_setting;
bool useU2X = true;
#if F_CPU == 16000000UL && SERIAL_PORT == 0
// Hard-coded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards, and the firmware on the
// 8U2 on the Uno and Mega 2560.
if (baud == 57600) useU2X = false;
#endif
R_UCSRA = 0;
if (useU2X) {
B_U2X = 1;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
}
else
baud_setting = (F_CPU / 8 / baud - 1) / 2;
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
R_UBRRH = baud_setting >> 8;
R_UBRRL = baud_setting;
B_RXEN = 1;
B_TXEN = 1;
B_RXCIE = 1;
if (Cfg::TX_SIZE > 0) B_UDRIE = 0;
_written = false;
}
template<typename Cfg>
void MarlinSerial<Cfg>::end() {
B_RXEN = 0;
B_TXEN = 0;
B_RXCIE = 0;
B_UDRIE = 0;
}
template<typename Cfg>
int MarlinSerial<Cfg>::peek() {
const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
return h == t ? -1 : rx_buffer.buffer[t];
}
template<typename Cfg>
int MarlinSerial<Cfg>::read() {
const ring_buffer_pos_t h = atomic_read_rx_head();
// Read the tail. Main thread owns it, so it is safe to directly read it
ring_buffer_pos_t t = rx_buffer.tail;
// If nothing to read, return now
if (h == t) return -1;
// Get the next char
const int v = rx_buffer.buffer[t];
t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1);
// Advance tail - Making sure the RX ISR will always get an stable value, even
// if it interrupts the writing of the value of that variable in the middle.
atomic_set_rx_tail(t);
if (Cfg::XONOFF) {
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
// Get count of bytes in the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
if (rx_count < (Cfg::RX_SIZE) / 10) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX ISR. Non atomic, but it will eventually enable them
B_UDRIE = 1;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!B_UDRE) sw_barrier();
R_UDR = XON_CHAR;
}
}
}
}
return v;
}
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::available() {
const ring_buffer_pos_t h = atomic_read_rx_head(), t = rx_buffer.tail;
return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1);
}
template<typename Cfg>
void MarlinSerial<Cfg>::flush() {
// Set the tail to the head:
// - Read the RX head index in a safe way. (See atomic_read_rx_head.)
// - Set the tail, making sure the RX ISR will always get a stable value, even
// if it interrupts the writing of the value of that variable in the middle.
atomic_set_rx_tail(atomic_read_rx_head());
if (Cfg::XONOFF) {
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX ISR. Non atomic, but it will eventually enable it.
B_UDRIE = 1;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!B_UDRE) sw_barrier();
R_UDR = XON_CHAR;
}
}
}
}
template<typename Cfg>
void MarlinSerial<Cfg>::write(const uint8_t c) {
if (Cfg::TX_SIZE == 0) {
_written = true;
while (!B_UDRE) sw_barrier();
R_UDR = c;
}
else {
_written = true;
// If the TX interrupts are disabled and the data register
// is empty, just write the byte to the data register and
// be done. This shortcut helps significantly improve the
// effective datarate at high (>500kbit/s) bitrates, where
// interrupt overhead becomes a slowdown.
// Yes, there is a race condition between the sending of the
// XOFF char at the RX ISR, but it is properly handled there
if (!B_UDRIE && B_UDRE) {
R_UDR = c;
// clear the TXC bit -- "can be cleared by writing a one to its bit
// location". This makes sure flush() won't return until the bytes
// actually got written
B_TXC = 1;
return;
}
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!hal.isr_state()) {
// Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) {
// If we can transmit another byte, do it.
if (B_UDRE) _tx_udr_empty_irq();
// Make sure compiler rereads tx_buffer.tail
sw_barrier();
}
}
else {
// Interrupts are enabled, just wait until there is space
while (i == tx_buffer.tail) sw_barrier();
}
// Store new char. head is always safe to move
tx_buffer.buffer[tx_buffer.head] = c;
tx_buffer.head = i;
// Enable TX ISR - Non atomic, but it will eventually enable TX ISR
B_UDRIE = 1;
}
}
template<typename Cfg>
void MarlinSerial<Cfg>::flushTX() {
if (Cfg::TX_SIZE == 0) {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// Wait until everything was transmitted
while (!B_TXC) sw_barrier();
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
else {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!hal.isr_state()) {
// Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !B_TXC) {
// If there is more space, send an extra character
if (B_UDRE) _tx_udr_empty_irq();
sw_barrier();
}
}
else {
// Wait until everything was transmitted
while (tx_buffer.head != tx_buffer.tail || !B_TXC) sw_barrier();
}
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
}
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
}
// Because of the template definition above, it's required to instantiate the template to have all methods generated
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MSerialT1 customizedSerial1(MSerialT1::HasEmergencyParser);
#ifdef SERIAL_PORT_2
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_2, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
MSerialT2 customizedSerial2(MSerialT2::HasEmergencyParser);
#endif // SERIAL_PORT_2
#ifdef SERIAL_PORT_3
// Hookup ISR handlers
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_3, _RX_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_3>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, SERIAL_PORT_3, _UDRE_vect)) {
MarlinSerial<MarlinSerialCfg<SERIAL_PORT_3>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> >;
MSerialT3 customizedSerial3(MSerialT3::HasEmergencyParser);
#endif // SERIAL_PORT_3
#ifdef MMU2_SERIAL_PORT
ISR(SERIAL_REGNAME(USART, MMU2_SERIAL_PORT, _RX_vect)) {
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, MMU2_SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq();
}
template class MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> >;
MSerialMMU2 mmuSerial(MSerialMMU2::HasEmergencyParser);
#endif // MMU2_SERIAL_PORT
#ifdef LCD_SERIAL_PORT
ISR(SERIAL_REGNAME(USART, LCD_SERIAL_PORT, _RX_vect)) {
MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::store_rxd_char();
}
ISR(SERIAL_REGNAME(USART, LCD_SERIAL_PORT, _UDRE_vect)) {
MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::_tx_udr_empty_irq();
}
template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
MSerialLCD lcdSerial(MSerialLCD::HasEmergencyParser);
#if HAS_DGUS_LCD
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
const ring_buffer_pos_t t = tx_buffer.tail, // next byte to send.
h = tx_buffer.head; // next pos for queue.
int ret = t - h - 1;
if (ret < 0) ret += Cfg::TX_SIZE + 1;
return ret;
}
#endif
#endif // LCD_SERIAL_PORT
#endif // !USBCON && (UBRRH || UBRR0H || UBRR1H || UBRR2H || UBRR3H)
// For AT90USB targets use the UART for BT interfacing
#if defined(USBCON) && ENABLED(BLUETOOTH)
MSerialBT bluetoothSerial(false);
#endif
#endif // __AVR__

297
src/HAL/AVR/MarlinSerial.h Normal file
View File

@ -0,0 +1,297 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* MarlinSerial.h - Hardware serial library for Wiring
* Copyright (c) 2006 Nicholas Zambetti. All right reserved.
*
* Modified 28 September 2010 by Mark Sproul
* Modified 14 February 2016 by Andreas Hardtung (added tx buffer)
* Modified 01 October 2017 by Eduardo José Tagle (added XON/XOFF)
* Templatized 01 October 2018 by Eduardo José Tagle to allow multiple instances
*/
#include <WString.h>
#include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
#ifndef SERIAL_PORT
#define SERIAL_PORT 0
#endif
#ifndef USBCON
// The presence of the UBRRH register is used to detect a UART.
#define UART_PRESENT(port) ((port == 0 && (defined(UBRRH) || defined(UBRR0H))) || \
(port == 1 && defined(UBRR1H)) || (port == 2 && defined(UBRR2H)) || \
(port == 3 && defined(UBRR3H)))
// These are macros to build serial port register names for the selected SERIAL_PORT (C preprocessor
// requires two levels of indirection to expand macro values properly)
#define SERIAL_REGNAME(registerbase,number,suffix) _SERIAL_REGNAME(registerbase,number,suffix)
#if SERIAL_PORT == 0 && (!defined(UBRR0H) || !defined(UDR0)) // use un-numbered registers if necessary
#define _SERIAL_REGNAME(registerbase,number,suffix) registerbase##suffix
#else
#define _SERIAL_REGNAME(registerbase,number,suffix) registerbase##number##suffix
#endif
// Registers used by MarlinSerial class (expanded depending on selected serial port)
// Templated 8bit register (generic)
#define UART_REGISTER_DECL_BASE(registerbase, suffix) \
template<int portNr> struct R_##registerbase##x##suffix {}
// Templated 8bit register (specialization for each port)
#define UART_REGISTER_DECL(port, registerbase, suffix) \
template<> struct R_##registerbase##x##suffix<port> { \
constexpr R_##registerbase##x##suffix(int) {} \
FORCE_INLINE void operator=(uint8_t newVal) const { SERIAL_REGNAME(registerbase,port,suffix) = newVal; } \
FORCE_INLINE operator uint8_t() const { return SERIAL_REGNAME(registerbase,port,suffix); } \
}
// Templated 1bit register (generic)
#define UART_BIT_DECL_BASE(registerbase, suffix, bit) \
template<int portNr>struct B_##bit##x {}
// Templated 1bit register (specialization for each port)
#define UART_BIT_DECL(port, registerbase, suffix, bit) \
template<> struct B_##bit##x<port> { \
constexpr B_##bit##x(int) {} \
FORCE_INLINE void operator=(int newVal) const { \
if (newVal) \
SBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \
else \
CBI(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); \
} \
FORCE_INLINE operator bool() const { return TEST(SERIAL_REGNAME(registerbase,port,suffix),SERIAL_REGNAME(bit,port,)); } \
}
#define UART_DECL_BASE() \
UART_REGISTER_DECL_BASE(UCSR,A);\
UART_REGISTER_DECL_BASE(UDR,);\
UART_REGISTER_DECL_BASE(UBRR,H);\
UART_REGISTER_DECL_BASE(UBRR,L);\
UART_BIT_DECL_BASE(UCSR,B,RXEN);\
UART_BIT_DECL_BASE(UCSR,B,TXEN);\
UART_BIT_DECL_BASE(UCSR,A,TXC);\
UART_BIT_DECL_BASE(UCSR,B,RXCIE);\
UART_BIT_DECL_BASE(UCSR,A,UDRE);\
UART_BIT_DECL_BASE(UCSR,A,FE);\
UART_BIT_DECL_BASE(UCSR,A,DOR);\
UART_BIT_DECL_BASE(UCSR,B,UDRIE);\
UART_BIT_DECL_BASE(UCSR,A,RXC);\
UART_BIT_DECL_BASE(UCSR,A,U2X)
#define UART_DECL(port) \
UART_REGISTER_DECL(port,UCSR,A);\
UART_REGISTER_DECL(port,UDR,);\
UART_REGISTER_DECL(port,UBRR,H);\
UART_REGISTER_DECL(port,UBRR,L);\
UART_BIT_DECL(port,UCSR,B,RXEN);\
UART_BIT_DECL(port,UCSR,B,TXEN);\
UART_BIT_DECL(port,UCSR,A,TXC);\
UART_BIT_DECL(port,UCSR,B,RXCIE);\
UART_BIT_DECL(port,UCSR,A,UDRE);\
UART_BIT_DECL(port,UCSR,A,FE);\
UART_BIT_DECL(port,UCSR,A,DOR);\
UART_BIT_DECL(port,UCSR,B,UDRIE);\
UART_BIT_DECL(port,UCSR,A,RXC);\
UART_BIT_DECL(port,UCSR,A,U2X)
// Declare empty templates
UART_DECL_BASE();
// And all the specializations for each possible serial port
#if UART_PRESENT(0)
UART_DECL(0);
#endif
#if UART_PRESENT(1)
UART_DECL(1);
#endif
#if UART_PRESENT(2)
UART_DECL(2);
#endif
#if UART_PRESENT(3)
UART_DECL(3);
#endif
#define BYTE 0
// Templated type selector
template<bool b, typename T, typename F> struct TypeSelector { typedef T type;} ;
template<typename T, typename F> struct TypeSelector<false, T, F> { typedef F type; };
template<typename Cfg>
class MarlinSerial {
protected:
// Registers
static constexpr R_UCSRxA<Cfg::PORT> R_UCSRA = 0;
static constexpr R_UDRx<Cfg::PORT> R_UDR = 0;
static constexpr R_UBRRxH<Cfg::PORT> R_UBRRH = 0;
static constexpr R_UBRRxL<Cfg::PORT> R_UBRRL = 0;
// Bits
static constexpr B_RXENx<Cfg::PORT> B_RXEN = 0;
static constexpr B_TXENx<Cfg::PORT> B_TXEN = 0;
static constexpr B_TXCx<Cfg::PORT> B_TXC = 0;
static constexpr B_RXCIEx<Cfg::PORT> B_RXCIE = 0;
static constexpr B_UDREx<Cfg::PORT> B_UDRE = 0;
static constexpr B_FEx<Cfg::PORT> B_FE = 0;
static constexpr B_DORx<Cfg::PORT> B_DOR = 0;
static constexpr B_UDRIEx<Cfg::PORT> B_UDRIE = 0;
static constexpr B_RXCx<Cfg::PORT> B_RXC = 0;
static constexpr B_U2Xx<Cfg::PORT> B_U2X = 0;
// Base size of type on buffer size
typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t;
struct ring_buffer_r {
volatile ring_buffer_pos_t head, tail;
unsigned char buffer[Cfg::RX_SIZE];
};
struct ring_buffer_t {
volatile uint8_t head, tail;
unsigned char buffer[Cfg::TX_SIZE];
};
static ring_buffer_r rx_buffer;
static ring_buffer_t tx_buffer;
static bool _written;
static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent
XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send
// XON / XOFF character definitions
static constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19;
static uint8_t xon_xoff_state,
rx_dropped_bytes,
rx_buffer_overruns,
rx_framing_errors;
static ring_buffer_pos_t rx_max_enqueued;
FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_head();
static volatile bool rx_tail_value_not_stable;
static volatile uint16_t rx_tail_value_backup;
FORCE_INLINE static void atomic_set_rx_tail(ring_buffer_pos_t value);
FORCE_INLINE static ring_buffer_pos_t atomic_read_rx_tail();
public:
FORCE_INLINE static void store_rxd_char();
FORCE_INLINE static void _tx_udr_empty_irq();
public:
static void begin(const long);
static void end();
static int peek();
static int read();
static void flush();
static ring_buffer_pos_t available();
static void write(const uint8_t c);
static void flushTX();
#if HAS_DGUS_LCD
static ring_buffer_pos_t get_tx_buffer_free();
#endif
enum { HasEmergencyParser = Cfg::EMERGENCYPARSER };
static bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
};
template <uint8_t serial>
struct MarlinSerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = RX_BUFFER_SIZE;
static constexpr unsigned int TX_SIZE = TX_BUFFER_SIZE;
static constexpr bool XONOFF = ENABLED(SERIAL_XON_XOFF);
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool DROPPED_RX = ENABLED(SERIAL_STATS_DROPPED_RX);
static constexpr bool RX_OVERRUNS = ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS);
static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT1;
extern MSerialT1 customizedSerial1;
#ifdef SERIAL_PORT_2
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
#ifdef SERIAL_PORT_3
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> > > MSerialT3;
extern MSerialT3 customizedSerial3;
#endif
#endif // !USBCON
#ifdef MMU2_SERIAL_PORT
template <uint8_t serial>
struct MMU2SerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = 32;
static constexpr unsigned int TX_SIZE = 32;
static constexpr bool XONOFF = false;
static constexpr bool EMERGENCYPARSER = false;
static constexpr bool DROPPED_RX = false;
static constexpr bool RX_FRAMING_ERRORS = false;
static constexpr bool MAX_RX_QUEUED = false;
static constexpr bool RX_OVERRUNS = false;
};
typedef Serial1Class< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialMMU2;
extern MSerialMMU2 mmuSerial;
#endif
#ifdef LCD_SERIAL_PORT
template <uint8_t serial>
struct LCDSerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = TERN(HAS_DGUS_LCD, DGUS_RX_BUFFER_SIZE, 64);
static constexpr unsigned int TX_SIZE = TERN(HAS_DGUS_LCD, DGUS_TX_BUFFER_SIZE, 128);
static constexpr bool XONOFF = false;
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool DROPPED_RX = false;
static constexpr bool RX_FRAMING_ERRORS = false;
static constexpr bool MAX_RX_QUEUED = false;
static constexpr bool RX_OVERRUNS = BOTH(HAS_DGUS_LCD, SERIAL_STATS_RX_BUFFER_OVERRUNS);
};
typedef Serial1Class< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialLCD;
extern MSerialLCD lcdSerial;
#endif
// Use the UART for Bluetooth in AT90USB configurations
#if defined(USBCON) && ENABLED(BLUETOOTH)
typedef Serial1Class<HardwareSerial> MSerialBT;
extern MSerialBT bluetoothSerial;
#endif

226
src/HAL/AVR/Servo.cpp Normal file
View File

@ -0,0 +1,226 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
* Copyright (c) 2009 Michael Margolis. All right reserved.
*/
/**
* A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
* The servos are pulsed in the background using the value most recently written using the write() method
*
* Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
* Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
*
* The methods are:
*
* Servo - Class for manipulating servo motors connected to Arduino pins.
*
* attach(pin) - Attach a servo motor to an i/o pin.
* attach(pin, min, max) - Attach to a pin, setting min and max values in microseconds
* Default min is 544, max is 2400
*
* write() - Set the servo angle in degrees. (Invalid angles over MIN_PULSE_WIDTH are treated as µs.)
* writeMicroseconds() - Set the servo pulse width in microseconds.
* move(pin, angle) - Sequence of attach(pin), write(angle), safe_delay(servo_delay[servoIndex]).
* With DEACTIVATE_SERVOS_AFTER_MOVE it detaches after servo_delay[servoIndex].
* read() - Get the last-written servo pulse width as an angle between 0 and 180.
* readMicroseconds() - Get the last-written servo pulse width in microseconds.
* attached() - Return true if a servo is attached.
* detach() - Stop an attached servo from pulsing its i/o pin.
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
#include <avr/interrupt.h>
#include "../shared/servo.h"
#include "../shared/servo_private.h"
static volatile int8_t Channel[_Nbr_16timers]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
/************ static functions common to all instances ***********************/
static inline void handle_interrupts(const timer16_Sequence_t timer, volatile uint16_t* TCNTn, volatile uint16_t* OCRnA) {
int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
if (cho < 0) // Channel -1 indicates the refresh interval completed...
*TCNTn = 0; // ...so reset the timer
else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
Channel[timer] = ++cho; // Handle the next channel (or 0)
if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
*OCRnA = *TCNTn + SERVO(timer, cho).ticks; // set compare to current ticks plus duration
if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
}
else {
// finished all channels so wait for the refresh period to expire before starting over
const unsigned int cval = ((unsigned)*TCNTn) + 32 / (SERVO_TIMER_PRESCALER), // allow 32 cycles to ensure the next OCR1A not missed
ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
*OCRnA = max(cval, ival);
Channel[timer] = -1; // reset the timer counter to 0 on the next call
}
}
#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
// Interrupt handlers for Arduino
#ifdef _useTimer1
SIGNAL(TIMER1_COMPA_vect) { handle_interrupts(_timer1, &TCNT1, &OCR1A); }
#endif
#ifdef _useTimer3
SIGNAL(TIMER3_COMPA_vect) { handle_interrupts(_timer3, &TCNT3, &OCR3A); }
#endif
#ifdef _useTimer4
SIGNAL(TIMER4_COMPA_vect) { handle_interrupts(_timer4, &TCNT4, &OCR4A); }
#endif
#ifdef _useTimer5
SIGNAL(TIMER5_COMPA_vect) { handle_interrupts(_timer5, &TCNT5, &OCR5A); }
#endif
#else // WIRING
// Interrupt handlers for Wiring
#ifdef _useTimer1
void Timer1Service() { handle_interrupts(_timer1, &TCNT1, &OCR1A); }
#endif
#ifdef _useTimer3
void Timer3Service() { handle_interrupts(_timer3, &TCNT3, &OCR3A); }
#endif
#endif // WIRING
/****************** end of static functions ******************************/
void initISR(const timer16_Sequence_t timer_index) {
switch (timer_index) {
default: break;
#ifdef _useTimer1
case _timer1:
TCCR1A = 0; // normal counting mode
TCCR1B = _BV(CS11); // set prescaler of 8
TCNT1 = 0; // clear the timer count
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
SBI(TIFR, OCF1A); // clear any pending interrupts;
SBI(TIMSK, OCIE1A); // enable the output compare interrupt
#else
// here if not ATmega8 or ATmega128
SBI(TIFR1, OCF1A); // clear any pending interrupts;
SBI(TIMSK1, OCIE1A); // enable the output compare interrupt
#endif
#ifdef WIRING
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
#endif
break;
#endif
#ifdef _useTimer3
case _timer3:
TCCR3A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8
TCNT3 = 0; // clear the timer count
#ifdef __AVR_ATmega128__
SBI(TIFR, OCF3A); // clear any pending interrupts;
SBI(ETIMSK, OCIE3A); // enable the output compare interrupt
#else
SBI(TIFR3, OCF3A); // clear any pending interrupts;
SBI(TIMSK3, OCIE3A); // enable the output compare interrupt
#endif
#ifdef WIRING
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
#endif
break;
#endif
#ifdef _useTimer4
case _timer4:
TCCR4A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8
TCNT4 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK4 = _BV(OCIE4A); // enable the output compare interrupt
break;
#endif
#ifdef _useTimer5
case _timer5:
TCCR5A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8
TCNT5 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A); // enable the output compare interrupt
break;
#endif
}
}
void finISR(const timer16_Sequence_t timer_index) {
// Disable use of the given timer
#ifdef WIRING
switch (timer_index) {
default: break;
case _timer1:
CBI(
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
TIMSK1
#else
TIMSK
#endif
, OCIE1A // disable timer 1 output compare interrupt
);
timerDetach(TIMER1OUTCOMPAREA_INT);
break;
case _timer3:
CBI(
#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
TIMSK3
#else
ETIMSK
#endif
, OCIE3A // disable the timer3 output compare A interrupt
);
timerDetach(TIMER3OUTCOMPAREA_INT);
break;
}
#else // !WIRING
// For arduino - in future: call here to a currently undefined function to reset the timer
UNUSED(timer_index);
#endif
}
#endif // HAS_SERVOS
#endif // __AVR__

93
src/HAL/AVR/ServoTimers.h Normal file
View File

@ -0,0 +1,93 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* ServoTimers.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
* Copyright (c) 2009 Michael Margolis. 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
*/
/**
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
/**
* AVR Only definitions
* --------------------
*/
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
#define SERVO_TIMER_PRESCALER 8 // timer prescaler
// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
//#define _useTimer1
#define _useTimer4
#if NUM_SERVOS > SERVOS_PER_TIMER
#define _useTimer3
#if !HAS_MOTOR_CURRENT_PWM && SERVOS > 2 * SERVOS_PER_TIMER
#define _useTimer5 // Timer 5 is used for motor current PWM and can't be used for servos.
#endif
#endif
#elif defined(__AVR_ATmega32U4__)
#define _useTimer3
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#else
// everything else
#endif
typedef enum {
#ifdef _useTimer1
_timer1,
#endif
#ifdef _useTimer3
_timer3,
#endif
#ifdef _useTimer4
_timer4,
#endif
#ifdef _useTimer5
_timer5,
#endif
_Nbr_16timers
} timer16_Sequence_t;

74
src/HAL/AVR/eeprom.cpp Normal file
View File

@ -0,0 +1,74 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
#if EITHER(EEPROM_SETTINGS, SD_FIRMWARE_UPDATE)
/**
* PersistentStore for Arduino-style EEPROM interface
* with implementations supplied by the framework.
*/
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE size_t(E2END + 1)
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
eeprom_write_byte(p, v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((uint8_t*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false; // always assume success for AVR's
}
#endif // EEPROM_SETTINGS || SD_FIRMWARE_UPDATE
#endif // __AVR__

View File

@ -0,0 +1,306 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Endstop Interrupts
*
* Without endstop interrupts the endstop pins must be polled continually in
* the temperature-ISR via endstops.update(), most of the time finding no change.
* With this feature endstops.update() is called only when we know that at
* least one endstop has changed state, saving valuable CPU cycles.
*
* This feature only works when all used endstop pins can generate either an
* 'external interrupt' or a 'pin change interrupt'.
*
* Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'.
* (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino)
*/
#include "../../module/endstops.h"
#include <stdint.h>
// One ISR for all EXT-Interrupts
void endstop_ISR() { endstops.update(); }
/**
* Patch for pins_arduino.h (...\Arduino\hardware\arduino\avr\variants\mega\pins_arduino.h)
*
* These macros for the Arduino MEGA do not include the two connected pins on Port J (D14, D15).
* So we extend them here because these are the normal pins for Y_MIN and Y_MAX on RAMPS.
* There are more PCI-enabled processor pins on Port J, but they are not connected to Arduino MEGA.
*/
#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_MEGA)
#define digitalPinHasPCICR(p) (WITHIN(p, 10, 15) || WITHIN(p, 50, 53) || WITHIN(p, 62, 69))
#undef digitalPinToPCICR
#define digitalPinToPCICR(p) (digitalPinHasPCICR(p) ? (&PCICR) : nullptr)
#undef digitalPinToPCICRbit
#define digitalPinToPCICRbit(p) (WITHIN(p, 10, 13) || WITHIN(p, 50, 53) ? 0 : \
WITHIN(p, 14, 15) ? 1 : \
WITHIN(p, 62, 69) ? 2 : \
0)
#undef digitalPinToPCMSK
#define digitalPinToPCMSK(p) (WITHIN(p, 10, 13) || WITHIN(p, 50, 53) ? (&PCMSK0) : \
WITHIN(p, 14, 15) ? (&PCMSK1) : \
WITHIN(p, 62, 69) ? (&PCMSK2) : \
nullptr)
#undef digitalPinToPCMSKbit
#define digitalPinToPCMSKbit(p) (WITHIN(p, 10, 13) ? ((p) - 6) : \
(p) == 14 || (p) == 51 ? 2 : \
(p) == 15 || (p) == 52 ? 1 : \
(p) == 50 ? 3 : \
(p) == 53 ? 0 : \
WITHIN(p, 62, 69) ? ((p) - 62) : \
0)
#elif defined(__AVR_ATmega164A__) || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324A__) || \
defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega324PB__) || \
defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || \
defined(__AVR_ATmega1284P__)
#define digitalPinHasPCICR(p) WITHIN(p, 0, NUM_DIGITAL_PINS)
#else
#error "Unsupported AVR variant!"
#endif
// Install Pin change interrupt for a pin. Can be called multiple times.
void pciSetup(const int8_t pin) {
if (digitalPinHasPCICR(pin)) {
SBI(*digitalPinToPCMSK(pin), digitalPinToPCMSKbit(pin)); // enable pin
SBI(PCIFR, digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
SBI(PCICR, digitalPinToPCICRbit(pin)); // enable interrupt for the group
}
}
// Handlers for pin change interrupts
#ifdef PCINT0_vect
ISR(PCINT0_vect) { endstop_ISR(); }
#endif
#ifdef PCINT1_vect
ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));
#endif
#ifdef PCINT2_vect
ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect));
#endif
#ifdef PCINT3_vect
ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect));
#endif
void setup_endstop_interrupts() {
#define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE)
#if HAS_X_MAX
#if (digitalPinToInterrupt(X_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(X_MAX_PIN), "X_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X_MAX_PIN);
#endif
#endif
#if HAS_X_MIN
#if (digitalPinToInterrupt(X_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(X_MIN_PIN), "X_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X_MIN_PIN);
#endif
#endif
#if HAS_Y_MAX
#if (digitalPinToInterrupt(Y_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Y_MAX_PIN), "Y_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y_MAX_PIN);
#endif
#endif
#if HAS_Y_MIN
#if (digitalPinToInterrupt(Y_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Y_MIN_PIN), "Y_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y_MIN_PIN);
#endif
#endif
#if HAS_Z_MAX
#if (digitalPinToInterrupt(Z_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z_MAX_PIN), "Z_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MAX_PIN);
#endif
#endif
#if HAS_Z_MIN
#if (digitalPinToInterrupt(Z_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z_MIN_PIN), "Z_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MIN_PIN);
#endif
#endif
#if HAS_I_MAX
#if (digitalPinToInterrupt(I_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(I_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(I_MAX_PIN), "I_MAX_PIN is not interrupt-capable");
pciSetup(I_MAX_PIN);
#endif
#elif HAS_I_MIN
#if (digitalPinToInterrupt(I_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(I_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(I_MIN_PIN), "I_MIN_PIN is not interrupt-capable");
pciSetup(I_MIN_PIN);
#endif
#endif
#if HAS_J_MAX
#if (digitalPinToInterrupt(J_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(J_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(J_MAX_PIN), "J_MAX_PIN is not interrupt-capable");
pciSetup(J_MAX_PIN);
#endif
#elif HAS_J_MIN
#if (digitalPinToInterrupt(J_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(J_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(J_MIN_PIN), "J_MIN_PIN is not interrupt-capable");
pciSetup(J_MIN_PIN);
#endif
#endif
#if HAS_K_MAX
#if (digitalPinToInterrupt(K_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(K_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(K_MAX_PIN), "K_MAX_PIN is not interrupt-capable");
pciSetup(K_MAX_PIN);
#endif
#elif HAS_K_MIN
#if (digitalPinToInterrupt(K_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(K_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(K_MIN_PIN), "K_MIN_PIN is not interrupt-capable");
pciSetup(K_MIN_PIN);
#endif
#endif
#if HAS_X2_MAX
#if (digitalPinToInterrupt(X2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X2_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(X2_MAX_PIN), "X2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X2_MAX_PIN);
#endif
#endif
#if HAS_X2_MIN
#if (digitalPinToInterrupt(X2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(X2_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(X2_MIN_PIN), "X2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(X2_MIN_PIN);
#endif
#endif
#if HAS_Y2_MAX
#if (digitalPinToInterrupt(Y2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y2_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Y2_MAX_PIN), "Y2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y2_MAX_PIN);
#endif
#endif
#if HAS_Y2_MIN
#if (digitalPinToInterrupt(Y2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Y2_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Y2_MIN_PIN), "Y2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Y2_MIN_PIN);
#endif
#endif
#if HAS_Z2_MAX
#if (digitalPinToInterrupt(Z2_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z2_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z2_MAX_PIN), "Z2_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z2_MAX_PIN);
#endif
#endif
#if HAS_Z2_MIN
#if (digitalPinToInterrupt(Z2_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z2_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z2_MIN_PIN), "Z2_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z2_MIN_PIN);
#endif
#endif
#if HAS_Z3_MAX
#if (digitalPinToInterrupt(Z3_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z3_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z3_MAX_PIN), "Z3_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z3_MAX_PIN);
#endif
#endif
#if HAS_Z3_MIN
#if (digitalPinToInterrupt(Z3_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z3_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z3_MIN_PIN), "Z3_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z3_MIN_PIN);
#endif
#endif
#if HAS_Z4_MAX
#if (digitalPinToInterrupt(Z4_MAX_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z4_MAX_PIN);
#else
static_assert(digitalPinHasPCICR(Z4_MAX_PIN), "Z4_MAX_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z4_MAX_PIN);
#endif
#endif
#if HAS_Z4_MIN
#if (digitalPinToInterrupt(Z4_MIN_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z4_MIN_PIN);
#else
static_assert(digitalPinHasPCICR(Z4_MIN_PIN), "Z4_MIN_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z4_MIN_PIN);
#endif
#endif
#if HAS_Z_MIN_PROBE_PIN
#if (digitalPinToInterrupt(Z_MIN_PROBE_PIN) != NOT_AN_INTERRUPT)
_ATTACH(Z_MIN_PROBE_PIN);
#else
static_assert(digitalPinHasPCICR(Z_MIN_PROBE_PIN), "Z_MIN_PROBE_PIN is not interrupt-capable. Disable ENDSTOP_INTERRUPTS_FEATURE to continue.");
pciSetup(Z_MIN_PROBE_PIN);
#endif
#endif
// If we arrive here without raising an assertion, each pin has either an EXT-interrupt or a PCI.
}

222
src/HAL/AVR/fast_pwm.cpp Normal file
View File

@ -0,0 +1,222 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef __AVR__
#include "../../inc/MarlinConfig.h"
struct Timer {
volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer
volatile uint16_t* OCRnQ[3]; // max 3 OCR registers per timer
volatile uint16_t* ICRn; // max 1 ICR register per timer
uint8_t n; // the timer number [0->5]
uint8_t q; // the timer output [0->2] (A->C)
bool isPWM; // True if pin is a "hardware timer"
bool isProtected; // True if timer is protected
};
// Macros for the Timer structure
#define _SET_WGMnQ(T, V) do{ \
*(T.TCCRnQ)[0] = (*(T.TCCRnQ)[0] & ~(0x3 << 0)) | (( int(V) & 0x3) << 0); \
*(T.TCCRnQ)[1] = (*(T.TCCRnQ)[1] & ~(0x3 << 3)) | (((int(V) >> 2) & 0x3) << 3); \
}while(0)
// Set TCCR CS bits
#define _SET_CSn(T, V) (*(T.TCCRnQ)[1] = (*(T.TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0))
// Set TCCR COM bits
#define _SET_COMnQ(T, Q, V) (*(T.TCCRnQ)[0] = (*(T.TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q))))
// Set OCRnQ register
#define _SET_OCRnQ(T, Q, V) (*(T.OCRnQ)[Q] = int(V) & 0xFFFF)
// Set ICRn register (one per timer)
#define _SET_ICRn(T, V) (*(T.ICRn) = int(V) & 0xFFFF)
/**
* Return a Timer struct describing a pin's timer.
*/
const Timer get_pwm_timer(const pin_t pin) {
uint8_t q = 0;
switch (digitalPinToTimer(pin)) {
#ifdef TCCR0A
IF_DISABLED(AVR_AT90USB1286_FAMILY, case TIMER0A:)
#endif
#ifdef TCCR1A
case TIMER1A: case TIMER1B:
#endif
break; // Protect reserved timers (TIMER0 & TIMER1)
#ifdef TCCR0A
case TIMER0B: // Protected timer, but allow setting the duty cycle on OCR0B for pin D4 only
return Timer({ { &TCCR0A, nullptr, nullptr }, { (uint16_t*)&OCR0A, (uint16_t*)&OCR0B, nullptr }, nullptr, 0, 1, true, true });
#endif
#if HAS_TCCR2
case TIMER2:
return Timer({ { &TCCR2, nullptr, nullptr }, { (uint16_t*)&OCR2, nullptr, nullptr }, nullptr, 2, 0, true, false });
#elif ENABLED(USE_OCR2A_AS_TOP)
case TIMER2A: break; // Protect TIMER2A since its OCR is used by TIMER2B
case TIMER2B:
return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, 1, true, false });
#elif defined(TCCR2A)
case TIMER2B: ++q; case TIMER2A:
return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, q, true, false });
#endif
#ifdef OCR3C
case TIMER3C: ++q; case TIMER3B: ++q; case TIMER3A:
return Timer({ { &TCCR3A, &TCCR3B, &TCCR3C }, { &OCR3A, &OCR3B, &OCR3C }, &ICR3, 3, q, true, false });
#elif defined(OCR3B)
case TIMER3B: ++q; case TIMER3A:
return Timer({ { &TCCR3A, &TCCR3B, nullptr }, { &OCR3A, &OCR3B, nullptr }, &ICR3, 3, q, true, false });
#endif
#ifdef TCCR4A
case TIMER4C: ++q; case TIMER4B: ++q; case TIMER4A:
return Timer({ { &TCCR4A, &TCCR4B, &TCCR4C }, { &OCR4A, &OCR4B, &OCR4C }, &ICR4, 4, q, true, false });
#endif
#ifdef TCCR5A
case TIMER5C: ++q; case TIMER5B: ++q; case TIMER5A:
return Timer({ { &TCCR5A, &TCCR5B, &TCCR5C }, { &OCR5A, &OCR5B, &OCR5C }, &ICR5, 5, q, true, false });
#endif
}
return Timer();
}
void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
const Timer timer = get_pwm_timer(pin);
if (timer.isProtected || !timer.isPWM) return; // Don't proceed if protected timer or not recognized
const bool is_timer2 = timer.n == 2;
const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF;
uint16_t res = 0xFF; // resolution (TOP value)
uint8_t j = CS_NONE; // prescaler index
uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode
// Calculating the prescaler and resolution to use to achieve closest frequency
if (f_desired != 0) {
constexpr uint16_t prescaler[] = { 1, 8, (32), 64, (128), 256, 1024 }; // (*) are Timer 2 only
uint16_t f = (F_CPU) / (2 * 1024 * maxtop) + 1; // Start with the lowest non-zero frequency achievable (1 or 31)
LOOP_L_N(i, COUNT(prescaler)) { // Loop through all prescaler values
const uint16_t p = prescaler[i];
uint16_t res_fast_temp, res_pc_temp;
if (is_timer2) {
#if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP
const uint16_t rft = (F_CPU) / (p * f_desired);
res_fast_temp = rft - 1;
res_pc_temp = rft / 2;
#else
res_fast_temp = res_pc_temp = maxtop;
#endif
}
else {
if (p == 32 || p == 128) continue; // Skip TIMER2 specific prescalers when not TIMER2
const uint16_t rft = (F_CPU) / (p * f_desired);
res_fast_temp = rft - 1;
res_pc_temp = rft / 2;
}
LIMIT(res_fast_temp, 1U, maxtop);
LIMIT(res_pc_temp, 1U, maxtop);
// Calculate frequencies of test prescaler and resolution values
const uint32_t f_diff = _MAX(f, f_desired) - _MIN(f, f_desired),
f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)),
f_fast_diff = _MAX(f_fast_temp, f_desired) - _MIN(f_fast_temp, f_desired),
f_pc_temp = (F_CPU) / (2 * p * res_pc_temp),
f_pc_diff = _MAX(f_pc_temp, f_desired) - _MIN(f_pc_temp, f_desired);
if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f
// Set the Wave Generation Mode to FAST PWM
wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t(WGM_FAST_PWM_ICRn);
// Remember this combination
f = f_fast_temp; res = res_fast_temp; j = i + 1;
}
else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f
// Set the Wave Generation Mode to PWM PHASE CORRECT
wgm = is_timer2 ? uint8_t(TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t(WGM_PWM_PC_ICRn);
f = f_pc_temp; res = res_pc_temp; j = i + 1;
}
}
}
_SET_WGMnQ(timer, wgm);
_SET_CSn(timer, j);
if (is_timer2) {
TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer, 0, res)); // Set OCR2A value (TOP) = res
}
else
_SET_ICRn(timer, res); // Set ICRn value (TOP) = res
}
void MarlinHAL::set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
// If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
// Note that digitalWrite also disables PWM output for us (sets COM bit to 0)
if (v == 0)
digitalWrite(pin, invert);
else if (v == v_size)
digitalWrite(pin, !invert);
else {
const Timer timer = get_pwm_timer(pin);
if (timer.isPWM) {
if (timer.n == 0) {
_SET_COMnQ(timer, timer.q, COM_CLEAR_SET); // Only allow a TIMER0B select...
_SET_OCRnQ(timer, timer.q, v); // ...and OCR0B duty update. For output pin D4 no frequency changes are permitted.
}
else if (!timer.isProtected) {
const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
_SET_COMnQ(timer, SUM_TERN(HAS_TCCR2, timer.q, timer.q == 2), COM_CLEAR_SET + invert); // COM20 is on bit 4 of TCCR2, so +1 for q==2
_SET_OCRnQ(timer, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value
}
}
else
digitalWrite(pin, v < v_size / 2 ? LOW : HIGH);
}
}
void MarlinHAL::init_pwm_timers() {
// Init some timer frequencies to a default 1KHz
const pin_t pwm_pin[] = {
#ifdef __AVR_ATmega2560__
10, 5, 6, 46
#elif defined(__AVR_ATmega1280__)
12, 31
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284__)
15, 6
#elif defined(__AVR_AT90USB1286__) || defined(__AVR_mega64) || defined(__AVR_mega128)
16, 24
#endif
};
LOOP_L_N(i, COUNT(pwm_pin))
set_pwm_frequency(pwm_pin[i], 1000);
}
#endif // __AVR__

288
src/HAL/AVR/fastio.cpp Normal file
View File

@ -0,0 +1,288 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Fast I/O for extended pins
*/
#ifdef __AVR__
#include "fastio.h"
#ifdef FASTIO_EXT_START
#include "../shared/Marduino.h"
#define _IS_EXT(P) WITHIN(P, FASTIO_EXT_START, FASTIO_EXT_END)
void extDigitalWrite(const int8_t pin, const uint8_t state) {
#define _WCASE(N) case N: WRITE(N, state); break
switch (pin) {
default: digitalWrite(pin, state);
#if _IS_EXT(70)
_WCASE(70);
#endif
#if _IS_EXT(71)
_WCASE(71);
#endif
#if _IS_EXT(72)
_WCASE(72);
#endif
#if _IS_EXT(73)
_WCASE(73);
#endif
#if _IS_EXT(74)
_WCASE(74);
#endif
#if _IS_EXT(75)
_WCASE(75);
#endif
#if _IS_EXT(76)
_WCASE(76);
#endif
#if _IS_EXT(77)
_WCASE(77);
#endif
#if _IS_EXT(78)
_WCASE(78);
#endif
#if _IS_EXT(79)
_WCASE(79);
#endif
#if _IS_EXT(80)
_WCASE(80);
#endif
#if _IS_EXT(81)
_WCASE(81);
#endif
#if _IS_EXT(82)
_WCASE(82);
#endif
#if _IS_EXT(83)
_WCASE(83);
#endif
#if _IS_EXT(84)
_WCASE(84);
#endif
#if _IS_EXT(85)
_WCASE(85);
#endif
#if _IS_EXT(86)
_WCASE(86);
#endif
#if _IS_EXT(87)
_WCASE(87);
#endif
#if _IS_EXT(88)
_WCASE(88);
#endif
#if _IS_EXT(89)
_WCASE(89);
#endif
#if _IS_EXT(90)
_WCASE(90);
#endif
#if _IS_EXT(91)
_WCASE(91);
#endif
#if _IS_EXT(92)
_WCASE(92);
#endif
#if _IS_EXT(93)
_WCASE(93);
#endif
#if _IS_EXT(94)
_WCASE(94);
#endif
#if _IS_EXT(95)
_WCASE(95);
#endif
#if _IS_EXT(96)
_WCASE(96);
#endif
#if _IS_EXT(97)
_WCASE(97);
#endif
#if _IS_EXT(98)
_WCASE(98);
#endif
#if _IS_EXT(99)
_WCASE(99);
#endif
#if _IS_EXT(100)
_WCASE(100);
#endif
}
}
uint8_t extDigitalRead(const int8_t pin) {
#define _RCASE(N) case N: return READ(N)
switch (pin) {
default: return digitalRead(pin);
#if _IS_EXT(70)
_RCASE(70);
#endif
#if _IS_EXT(71)
_RCASE(71);
#endif
#if _IS_EXT(72)
_RCASE(72);
#endif
#if _IS_EXT(73)
_RCASE(73);
#endif
#if _IS_EXT(74)
_RCASE(74);
#endif
#if _IS_EXT(75)
_RCASE(75);
#endif
#if _IS_EXT(76)
_RCASE(76);
#endif
#if _IS_EXT(77)
_RCASE(77);
#endif
#if _IS_EXT(78)
_RCASE(78);
#endif
#if _IS_EXT(79)
_RCASE(79);
#endif
#if _IS_EXT(80)
_RCASE(80);
#endif
#if _IS_EXT(81)
_RCASE(81);
#endif
#if _IS_EXT(82)
_RCASE(82);
#endif
#if _IS_EXT(83)
_RCASE(83);
#endif
#if _IS_EXT(84)
_RCASE(84);
#endif
#if _IS_EXT(85)
_RCASE(85);
#endif
#if _IS_EXT(86)
_RCASE(86);
#endif
#if _IS_EXT(87)
_RCASE(87);
#endif
#if _IS_EXT(88)
_RCASE(88);
#endif
#if _IS_EXT(89)
_RCASE(89);
#endif
#if _IS_EXT(90)
_RCASE(90);
#endif
#if _IS_EXT(91)
_RCASE(91);
#endif
#if _IS_EXT(92)
_RCASE(92);
#endif
#if _IS_EXT(93)
_RCASE(93);
#endif
#if _IS_EXT(94)
_RCASE(94);
#endif
#if _IS_EXT(95)
_RCASE(95);
#endif
#if _IS_EXT(96)
_RCASE(96);
#endif
#if _IS_EXT(97)
_RCASE(97);
#endif
#if _IS_EXT(98)
_RCASE(98);
#endif
#if _IS_EXT(99)
_RCASE(99);
#endif
#if _IS_EXT(100)
_RCASE(100);
#endif
}
}
#if 0
/**
* Set Timer 5 PWM frequency in Hz, from 3.8Hz up to ~16MHz
* with a minimum resolution of 100 steps.
*
* DC values -1.0 to 1.0. Negative duty cycle inverts the pulse.
*/
uint16_t set_pwm_frequency_hz(const_float_t hz, const float dca, const float dcb, const float dcc) {
float count = 0;
if (hz > 0 && (dca || dcb || dcc)) {
count = float(F_CPU) / hz; // 1x prescaler, TOP for 16MHz base freq.
uint16_t prescaler; // Range of 30.5Hz (65535) 64.5kHz (>31)
if (count >= 255. * 256.) { prescaler = 1024; SET_CS(5, PRESCALER_1024); }
else if (count >= 255. * 64.) { prescaler = 256; SET_CS(5, PRESCALER_256); }
else if (count >= 255. * 8.) { prescaler = 64; SET_CS(5, PRESCALER_64); }
else if (count >= 255.) { prescaler = 8; SET_CS(5, PRESCALER_8); }
else { prescaler = 1; SET_CS(5, PRESCALER_1); }
count /= float(prescaler);
const float pwm_top = round(count); // Get the rounded count
ICR5 = (uint16_t)pwm_top - 1; // Subtract 1 for TOP
OCR5A = pwm_top * ABS(dca); // Update and scale DCs
OCR5B = pwm_top * ABS(dcb);
OCR5C = pwm_top * ABS(dcc);
_SET_COM(5, A, dca ? (dca < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL); // Set compare modes
_SET_COM(5, B, dcb ? (dcb < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL);
_SET_COM(5, C, dcc ? (dcc < 0 ? COM_SET_CLEAR : COM_CLEAR_SET) : COM_NORMAL);
SET_WGM(5, FAST_PWM_ICRn); // Fast PWM with ICR5 as TOP
//SERIAL_ECHOLNPGM("Timer 5 Settings:");
//SERIAL_ECHOLNPGM(" Prescaler=", prescaler);
//SERIAL_ECHOLNPGM(" TOP=", ICR5);
//SERIAL_ECHOLNPGM(" OCR5A=", OCR5A);
//SERIAL_ECHOLNPGM(" OCR5B=", OCR5B);
//SERIAL_ECHOLNPGM(" OCR5C=", OCR5C);
}
else {
// Restore the default for Timer 5
SET_WGM(5, PWM_PC_8); // PWM 8-bit (Phase Correct)
SET_COMS(5, NORMAL, NORMAL, NORMAL); // Do nothing
SET_CS(5, PRESCALER_64); // 16MHz / 64 = 250kHz
OCR5A = OCR5B = OCR5C = 0;
}
return round(count);
}
#endif
#endif // FASTIO_EXT_START
#endif // __AVR__

350
src/HAL/AVR/fastio.h Normal file
View File

@ -0,0 +1,350 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Fast I/O Routines for AVR
* Use direct port manipulation to save scads of processor time.
* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.
*/
#include <avr/io.h>
#if defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1286P__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB646P__) || defined(__AVR_AT90USB647__)
#define AVR_AT90USB1286_FAMILY 1
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
#define AVR_ATmega1284_FAMILY 1
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVR_ATmega2560_FAMILY 1
#elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
#define AVR_ATmega2561_FAMILY 1
#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#define AVR_ATmega328_FAMILY 1
#endif
/**
* Include Ports and Functions
*/
#if AVR_ATmega328_FAMILY
#include "fastio/fastio_168.h"
#elif AVR_ATmega1284_FAMILY
#include "fastio/fastio_644.h"
#elif AVR_ATmega2560_FAMILY
#include "fastio/fastio_1280.h"
#elif AVR_AT90USB1286_FAMILY
#include "fastio/fastio_AT90USB.h"
#elif AVR_ATmega2561_FAMILY
#include "fastio/fastio_1281.h"
#else
#error "No FastIO definition for the selected AVR Board."
#endif
/**
* Magic I/O routines
*
* Now you can simply SET_OUTPUT(PIN); WRITE(PIN, HIGH); WRITE(PIN, LOW);
*
* Why double up on these macros? see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
#define _READ(IO) TEST(DIO ## IO ## _RPORT, DIO ## IO ## _PIN)
#define _WRITE_NC(IO,V) do{ \
if (V) SBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \
else CBI(DIO ## IO ## _WPORT, DIO ## IO ## _PIN); \
}while(0)
#define _WRITE_C(IO,V) do{ \
uint8_t port_bits = DIO ## IO ## _WPORT; /* Get a mask from the current port bits */ \
if (V) port_bits = ~port_bits; /* For setting bits, invert the mask */ \
DIO ## IO ## _RPORT = port_bits & _BV(DIO ## IO ## _PIN); /* Atomically toggle the output port bits */ \
}while(0)
#define _WRITE(IO,V) do{ if (&(DIO ## IO ## _RPORT) < (uint8_t*)0x100) _WRITE_NC(IO,V); else _WRITE_C(IO,V); }while(0)
#define _TOGGLE(IO) (DIO ## IO ## _RPORT = _BV(DIO ## IO ## _PIN))
#define _SET_INPUT(IO) CBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
#define _SET_OUTPUT(IO) SBI(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
#define _IS_INPUT(IO) !TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
#define _IS_OUTPUT(IO) TEST(DIO ## IO ## _DDR, DIO ## IO ## _PIN)
// digitalRead/Write wrappers
#ifdef FASTIO_EXT_START
void extDigitalWrite(const int8_t pin, const uint8_t state);
uint8_t extDigitalRead(const int8_t pin);
#else
#define extDigitalWrite(IO,V) digitalWrite(IO,V)
#define extDigitalRead(IO) digitalRead(IO)
#endif
#define READ(IO) _READ(IO)
#define WRITE(IO,V) _WRITE(IO,V)
#define TOGGLE(IO) _TOGGLE(IO)
#define SET_INPUT(IO) _SET_INPUT(IO)
#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _WRITE(IO, HIGH); }while(0)
#define SET_INPUT_PULLDOWN SET_INPUT
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
#define SET_PWM SET_OUTPUT
#define IS_INPUT(IO) _IS_INPUT(IO)
#define IS_OUTPUT(IO) _IS_OUTPUT(IO)
#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
/**
* Timer and Interrupt Control
*/
// Waveform Generation Modes
enum WaveGenMode : uint8_t {
WGM_NORMAL, // 0
WGM_PWM_PC_8, // 1
WGM_PWM_PC_9, // 2
WGM_PWM_PC_10, // 3
WGM_CTC_OCRnA, // 4 COM OCnx
WGM_FAST_PWM_8, // 5
WGM_FAST_PWM_9, // 6
WGM_FAST_PWM_10, // 7
WGM_PWM_PC_FC_ICRn, // 8
WGM_PWM_PC_FC_OCRnA, // 9 COM OCnA
WGM_PWM_PC_ICRn, // 10
WGM_PWM_PC_OCRnA, // 11 COM OCnA
WGM_CTC_ICRn, // 12 COM OCnx
WGM_reserved, // 13
WGM_FAST_PWM_ICRn, // 14 COM OCnA
WGM_FAST_PWM_OCRnA // 15 COM OCnA
};
// Wavefore Generation Modes (Timer 2 only)
enum WaveGenMode2 : uint8_t {
WGM2_NORMAL, // 0
WGM2_PWM_PC, // 1
WGM2_CTC_OCR2A, // 2
WGM2_FAST_PWM, // 3
WGM2_reserved_1, // 4
WGM2_PWM_PC_OCR2A, // 5
WGM2_reserved_2, // 6
WGM2_FAST_PWM_OCR2A, // 7
};
// Compare Modes
enum CompareMode : uint8_t {
COM_NORMAL, // 0
COM_TOGGLE, // 1 Non-PWM: OCnx ... Both PWM (WGM 9,11,14,15): OCnA only ... else NORMAL
COM_CLEAR_SET, // 2 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down
COM_SET_CLEAR // 3 Non-PWM: OCnx ... Fast PWM: OCnx/Bottom ... PF-FC: OCnx Up/Down
};
// Clock Sources
enum ClockSource : uint8_t {
CS_NONE, // 0
CS_PRESCALER_1, // 1
CS_PRESCALER_8, // 2
CS_PRESCALER_64, // 3
CS_PRESCALER_256, // 4
CS_PRESCALER_1024, // 5
CS_EXT_FALLING, // 6
CS_EXT_RISING // 7
};
// Clock Sources (Timer 2 only)
enum ClockSource2 : uint8_t {
CS2_NONE, // 0
CS2_PRESCALER_1, // 1
CS2_PRESCALER_8, // 2
CS2_PRESCALER_32, // 3
CS2_PRESCALER_64, // 4
CS2_PRESCALER_128, // 5
CS2_PRESCALER_256, // 6
CS2_PRESCALER_1024 // 7
};
// Get interrupt bits in an orderly way
// Ex: cs = GET_CS(0); coma1 = GET_COM(A,1);
#define GET_WGM(T) (((TCCR##T##A >> WGM##T##0) & 0x3) | ((TCCR##T##B >> WGM##T##2 << 2) & 0xC))
#define GET_CS(T) ((TCCR##T##B >> CS##T##0) & 0x7)
#define GET_COM(T,Q) ((TCCR##T##Q >> COM##T##Q##0) & 0x3)
#define GET_COMA(T) GET_COM(T,A)
#define GET_COMB(T) GET_COM(T,B)
#define GET_COMC(T) GET_COM(T,C)
#define GET_ICNC(T) (!!(TCCR##T##B & _BV(ICNC##T)))
#define GET_ICES(T) (!!(TCCR##T##B & _BV(ICES##T)))
#define GET_FOC(T,Q) (!!(TCCR##T##C & _BV(FOC##T##Q)))
#define GET_FOCA(T) GET_FOC(T,A)
#define GET_FOCB(T) GET_FOC(T,B)
#define GET_FOCC(T) GET_FOC(T,C)
// Set Wave Generation Mode bits
// Ex: SET_WGM(5,CTC_ICRn);
#define _SET_WGM(T,V) do{ \
TCCR##T##A = (TCCR##T##A & ~(0x3 << WGM##T##0)) | (( int(V) & 0x3) << WGM##T##0); \
TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \
}while(0)
#define SET_WGM(T,V) _SET_WGM(T,WGM_##V)
// Set Clock Select bits
// Ex: SET_CS3(PRESCALER_64);
#ifdef TCCR2
#define HAS_TCCR2 1
#endif
#define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0))
#define _SET_CS0(V) _SET_CS(0,V)
#define _SET_CS1(V) _SET_CS(1,V)
#define _SET_CS3(V) _SET_CS(3,V)
#define _SET_CS4(V) _SET_CS(4,V)
#define _SET_CS5(V) _SET_CS(5,V)
#define SET_CS0(V) _SET_CS0(CS_##V)
#define SET_CS1(V) _SET_CS1(CS_##V)
#if HAS_TCCR2
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
#define SET_CS2(V) _SET_CS2(CS2_##V)
#else
#define _SET_CS2(V) _SET_CS(2,V)
#define SET_CS2(V) _SET_CS2(CS_##V)
#endif
#define SET_CS3(V) _SET_CS3(CS_##V)
#define SET_CS4(V) _SET_CS4(CS_##V)
#define SET_CS5(V) _SET_CS5(CS_##V)
#define SET_CS(T,V) SET_CS##T(V)
// Set Compare Mode bits
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
#define _SET_COM(T,Q,V) (TCCR##T##Q = (TCCR##T##Q & ~(0x3 << COM##T##Q##0)) | (int(V) << COM##T##Q##0))
#define SET_COM(T,Q,V) _SET_COM(T,Q,COM_##V)
#define SET_COMA(T,V) SET_COM(T,A,V)
#define SET_COMB(T,V) SET_COM(T,B,V)
#define SET_COMC(T,V) SET_COM(T,C,V)
#define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0)
// Set Noise Canceler bit
// Ex: SET_ICNC(2,1)
#define SET_ICNC(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICNC##T) : TCCR##T##B & ~_BV(ICNC##T))
// Set Input Capture Edge Select bit
// Ex: SET_ICES(5,0)
#define SET_ICES(T,V) (TCCR##T##B = (V) ? TCCR##T##B | _BV(ICES##T) : TCCR##T##B & ~_BV(ICES##T))
// Set Force Output Compare bit
// Ex: SET_FOC(3,A,1)
#define SET_FOC(T,Q,V) (TCCR##T##C = (V) ? TCCR##T##C | _BV(FOC##T##Q) : TCCR##T##C & ~_BV(FOC##T##Q))
#define SET_FOCA(T,V) SET_FOC(T,A,V)
#define SET_FOCB(T,V) SET_FOC(T,B,V)
#define SET_FOCC(T,V) SET_FOC(T,C,V)
#if 0
/**
* PWM availability macros
*/
// Determine which hardware PWMs are already in use
#define _PWM_CHK_FAN_B(P) (P == E0_AUTO_FAN_PIN || P == E1_AUTO_FAN_PIN || P == E2_AUTO_FAN_PIN || P == E3_AUTO_FAN_PIN || P == E4_AUTO_FAN_PIN || P == E5_AUTO_FAN_PIN || P == E6_AUTO_FAN_PIN || P == E7_AUTO_FAN_PIN || P == CHAMBER_AUTO_FAN_PIN || P == COOLER_AUTO_FAN_PIN)
#if PIN_EXISTS(CONTROLLER_FAN)
#define PWM_CHK_FAN_B(P) (_PWM_CHK_FAN_B(P) || P == CONTROLLER_FAN_PIN)
#else
#define PWM_CHK_FAN_B(P) _PWM_CHK_FAN_B(P)
#endif
#if ANY_PIN(FAN, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7)
#if PIN_EXISTS(FAN7)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN || P == FAN6_PIN || P == FAN7_PIN)
#elif PIN_EXISTS(FAN6)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN || P == FAN6_PIN)
#elif PIN_EXISTS(FAN5)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN || P == FAN5_PIN)
#elif PIN_EXISTS(FAN4)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN || P == FAN4_PIN)
#elif PIN_EXISTS(FAN3)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN || P == FAN3_PIN)
#elif PIN_EXISTS(FAN2)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN || P == FAN2_PIN)
#elif PIN_EXISTS(FAN1)
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN || P == FAN1_PIN)
#else
#define PWM_CHK_FAN_A(P) (P == FAN0_PIN)
#endif
#else
#define PWM_CHK_FAN_A(P) false
#endif
#if HAS_MOTOR_CURRENT_PWM
#if PIN_EXISTS(MOTOR_CURRENT_PWM_XY)
#define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_Z || P == MOTOR_CURRENT_PWM_XY)
#elif PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
#define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E || P == MOTOR_CURRENT_PWM_Z)
#else
#define PWM_CHK_MOTOR_CURRENT(P) (P == MOTOR_CURRENT_PWM_E)
#endif
#else
#define PWM_CHK_MOTOR_CURRENT(P) false
#endif
#ifdef NUM_SERVOS
#if AVR_ATmega2560_FAMILY
#define PWM_CHK_SERVO(P) (P == 5 || (NUM_SERVOS > 12 && P == 6) || (NUM_SERVOS > 24 && P == 46)) // PWMS 3A, 4A & 5A
#elif AVR_ATmega2561_FAMILY
#define PWM_CHK_SERVO(P) (P == 5) // PWM3A
#elif AVR_ATmega1284_FAMILY
#define PWM_CHK_SERVO(P) false
#elif AVR_AT90USB1286_FAMILY
#define PWM_CHK_SERVO(P) (P == 16) // PWM3A
#elif AVR_ATmega328_FAMILY
#define PWM_CHK_SERVO(P) false
#endif
#else
#define PWM_CHK_SERVO(P) false
#endif
#if ENABLED(BARICUDA)
#if HAS_HEATER_1 && HAS_HEATER_2
#define PWM_CHK_HEATER(P) (P == HEATER_1_PIN || P == HEATER_2_PIN)
#elif HAS_HEATER_1
#define PWM_CHK_HEATER(P) (P == HEATER_1_PIN)
#endif
#else
#define PWM_CHK_HEATER(P) false
#endif
#define PWM_CHK(P) (PWM_CHK_HEATER(P) || PWM_CHK_SERVO(P) || PWM_CHK_MOTOR_CURRENT(P) || PWM_CHK_FAN_A(P) || PWM_CHK_FAN_B(P))
#endif // PWM_CHK is not used in Marlin
// define which hardware PWMs are available for the current CPU
// all timer 1 PWMS deleted from this list because they are never available
#if AVR_ATmega2560_FAMILY
#define PWM_PIN(P) ((P >= 2 && P <= 10) || P == 13 || P == 44 || P == 45 || P == 46)
#elif AVR_ATmega2561_FAMILY
#define PWM_PIN(P) ((P >= 2 && P <= 6) || P == 9)
#elif AVR_ATmega1284_FAMILY
#define PWM_PIN(P) (P == 3 || P == 4 || P == 14 || P == 15)
#elif AVR_AT90USB1286_FAMILY
#define PWM_PIN(P) (P == 0 || P == 1 || P == 14 || P == 15 || P == 16 || P == 24)
#elif AVR_ATmega328_FAMILY
#define PWM_PIN(P) (P == 3 || P == 5 || P == 6 || P == 11)
#else
#error "unknown CPU"
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,715 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Pin mapping for the 1281 and 2561
*
* Logical Pin: 38 39 40 41 42 43 44 45 16 10 11 12 06 07 08 09 30 31 32 33 34 35 36 37 17 18 19 20 21 22 23 24 00 01 13 05 02 03 14 15 46 47 48 49 50 51 52 53 25 26 27 28 29 04
* Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7 G0 G1 G2 G3 G4 G5
*/
#include "../fastio.h"
// change for your board
#define DEBUG_LED DIO46
// UART
#define RXD DIO0
#define TXD DIO1
// SPI
#define SCK DIO10
#define MISO DIO12
#define MOSI DIO11
#define SS DIO16
// TWI (I2C)
#define SCL DIO17
#define SDA DIO18
// Timers and PWM
#define OC0A DIO9
#define OC0B DIO4
#define OC1A DIO7
#define OC1B DIO8
#define OC2A DIO6
#define OC3A DIO5
#define OC3B DIO2
#define OC3C DIO3
// Digital I/O
#define DIO0_PIN PINE0
#define DIO0_RPORT PINE
#define DIO0_WPORT PORTE
#define DIO0_DDR DDRE
#define DIO0_PWM nullptr
#define DIO1_PIN PINE1
#define DIO1_RPORT PINE
#define DIO1_WPORT PORTE
#define DIO1_DDR DDRE
#define DIO1_PWM nullptr
#define DIO2_PIN PINE4
#define DIO2_RPORT PINE
#define DIO2_WPORT PORTE
#define DIO2_DDR DDRE
#define DIO2_PWM &OCR3BL
#define DIO3_PIN PINE5
#define DIO3_RPORT PINE
#define DIO3_WPORT PORTE
#define DIO3_DDR DDRE
#define DIO3_PWM &OCR3CL
#define DIO4_PIN PING5
#define DIO4_RPORT PING
#define DIO4_WPORT PORTG
#define DIO4_DDR DDRG
#define DIO4_PWM &OCR0B
#define DIO5_PIN PINE3
#define DIO5_RPORT PINE
#define DIO5_WPORT PORTE
#define DIO5_DDR DDRE
#define DIO5_PWM &OCR3AL
#define DIO6_PIN PINB4
#define DIO6_RPORT PINB
#define DIO6_WPORT PORTB
#define DIO6_DDR DDRB
#define DIO6_PWM &OCR2AL
#define DIO7_PIN PINB5
#define DIO7_RPORT PINB
#define DIO7_WPORT PORTB
#define DIO7_DDR DDRB
#define DIO7_PWM &OCR1AL
#define DIO8_PIN PINB6
#define DIO8_RPORT PINB
#define DIO8_WPORT PORTB
#define DIO8_DDR DDRB
#define DIO8_PWM &OCR1BL
#define DIO9_PIN PINB7
#define DIO9_RPORT PINB
#define DIO9_WPORT PORTB
#define DIO9_DDR DDRB
#define DIO9_PWM &OCR0AL
#define DIO10_PIN PINB1
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM nullptr
#define DIO11_PIN PINB2
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM nullptr
#define DIO12_PIN PINB3
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
#define DIO13_PIN PINE2
#define DIO13_RPORT PINE
#define DIO13_WPORT PORTE
#define DIO13_DDR DDRE
#define DIO13_PWM nullptr
#define DIO14_PIN PINE6
#define DIO14_RPORT PINE
#define DIO14_WPORT PORTE
#define DIO14_DDR DDRE
#define DIO14_PWM nullptr
#define DIO15_PIN PINE7
#define DIO15_RPORT PINE
#define DIO15_WPORT PORTE
#define DIO15_DDR DDRE
#define DIO15_PWM nullptr
#define DIO16_PIN PINB0
#define DIO16_RPORT PINB
#define DIO16_WPORT PORTB
#define DIO16_DDR DDRB
#define DIO16_PWM nullptr
#define DIO17_PIN PIND0
#define DIO17_RPORT PIND
#define DIO17_WPORT PORTD
#define DIO17_DDR DDRD
#define DIO17_PWM nullptr
#define DIO18_PIN PIND1
#define DIO18_RPORT PIND
#define DIO18_WPORT PORTD
#define DIO18_DDR DDRD
#define DIO18_PWM nullptr
#define DIO19_PIN PIND2
#define DIO19_RPORT PIND
#define DIO19_WPORT PORTD
#define DIO19_DDR DDRD
#define DIO19_PWM nullptr
#define DIO20_PIN PIND3
#define DIO20_RPORT PIND
#define DIO20_WPORT PORTD
#define DIO20_DDR DDRD
#define DIO20_PWM nullptr
#define DIO21_PIN PIND4
#define DIO21_RPORT PIND
#define DIO21_WPORT PORTD
#define DIO21_DDR DDRD
#define DIO21_PWM nullptr
#define DIO22_PIN PIND5
#define DIO22_RPORT PIND
#define DIO22_WPORT PORTD
#define DIO22_DDR DDRD
#define DIO22_PWM nullptr
#define DIO23_PIN PIND6
#define DIO23_RPORT PIND
#define DIO23_WPORT PORTD
#define DIO23_DDR DDRD
#define DIO23_PWM nullptr
#define DIO24_PIN PIND7
#define DIO24_RPORT PIND
#define DIO24_WPORT PORTD
#define DIO24_DDR DDRD
#define DIO24_PWM nullptr
#define DIO25_PIN PING0
#define DIO25_RPORT PING
#define DIO25_WPORT PORTG
#define DIO25_DDR DDRG
#define DIO25_PWM nullptr
#define DIO26_PIN PING1
#define DIO26_RPORT PING
#define DIO26_WPORT PORTG
#define DIO26_DDR DDRG
#define DIO26_PWM nullptr
#define DIO27_PIN PING2
#define DIO27_RPORT PING
#define DIO27_WPORT PORTG
#define DIO27_DDR DDRG
#define DIO27_PWM nullptr
#define DIO28_PIN PING3
#define DIO28_RPORT PING
#define DIO28_WPORT PORTG
#define DIO28_DDR DDRG
#define DIO28_PWM nullptr
#define DIO29_PIN PING4
#define DIO29_RPORT PING
#define DIO29_WPORT PORTG
#define DIO29_DDR DDRG
#define DIO29_PWM nullptr
#define DIO30_PIN PINC0
#define DIO30_RPORT PINC
#define DIO30_WPORT PORTC
#define DIO30_DDR DDRC
#define DIO30_PWM nullptr
#define DIO31_PIN PINC1
#define DIO31_RPORT PINC
#define DIO31_WPORT PORTC
#define DIO31_DDR DDRC
#define DIO31_PWM nullptr
#define DIO32_PIN PINC2
#define DIO32_RPORT PINC
#define DIO32_WPORT PORTC
#define DIO32_DDR DDRC
#define DIO32_PWM nullptr
#define DIO33_PIN PINC3
#define DIO33_RPORT PINC
#define DIO33_WPORT PORTC
#define DIO33_DDR DDRC
#define DIO33_PWM nullptr
#define DIO34_PIN PINC4
#define DIO34_RPORT PINC
#define DIO34_WPORT PORTC
#define DIO34_DDR DDRC
#define DIO34_PWM nullptr
#define DIO35_PIN PINC5
#define DIO35_RPORT PINC
#define DIO35_WPORT PORTC
#define DIO35_DDR DDRC
#define DIO35_PWM nullptr
#define DIO36_PIN PINC6
#define DIO36_RPORT PINC
#define DIO36_WPORT PORTC
#define DIO36_DDR DDRC
#define DIO36_PWM nullptr
#define DIO37_PIN PINC7
#define DIO37_RPORT PINC
#define DIO37_WPORT PORTC
#define DIO37_DDR DDRC
#define DIO37_PWM nullptr
#define DIO38_PIN PINA0
#define DIO38_RPORT PINA
#define DIO38_WPORT PORTA
#define DIO38_DDR DDRA
#define DIO38_PWM nullptr
#define DIO39_PIN PINA1
#define DIO39_RPORT PINA
#define DIO39_WPORT PORTA
#define DIO39_DDR DDRA
#define DIO39_PWM nullptr
#define DIO40_PIN PINA2
#define DIO40_RPORT PINA
#define DIO40_WPORT PORTA
#define DIO40_DDR DDRA
#define DIO40_PWM nullptr
#define DIO41_PIN PINA3
#define DIO41_RPORT PINA
#define DIO41_WPORT PORTA
#define DIO41_DDR DDRA
#define DIO41_PWM nullptr
#define DIO42_PIN PINA4
#define DIO42_RPORT PINA
#define DIO42_WPORT PORTA
#define DIO42_DDR DDRA
#define DIO42_PWM nullptr
#define DIO43_PIN PINA5
#define DIO43_RPORT PINA
#define DIO43_WPORT PORTA
#define DIO43_DDR DDRA
#define DIO43_PWM nullptr
#define DIO44_PIN PINA6
#define DIO44_RPORT PINA
#define DIO44_WPORT PORTA
#define DIO44_DDR DDRA
#define DIO44_PWM nullptr
#define DIO45_PIN PINA7
#define DIO45_RPORT PINA
#define DIO45_WPORT PORTA
#define DIO45_DDR DDRA
#define DIO45_PWM nullptr
#define DIO46_PIN PINF0
#define DIO46_RPORT PINF
#define DIO46_WPORT PORTF
#define DIO46_DDR DDRF
#define DIO46_PWM nullptr
#define DIO47_PIN PINF1
#define DIO47_RPORT PINF
#define DIO47_WPORT PORTF
#define DIO47_DDR DDRF
#define DIO47_PWM nullptr
#define DIO48_PIN PINF2
#define DIO48_RPORT PINF
#define DIO48_WPORT PORTF
#define DIO48_DDR DDRF
#define DIO48_PWM nullptr
#define DIO49_PIN PINF3
#define DIO49_RPORT PINF
#define DIO49_WPORT PORTF
#define DIO49_DDR DDRF
#define DIO49_PWM nullptr
#define DIO50_PIN PINF4
#define DIO50_RPORT PINF
#define DIO50_WPORT PORTF
#define DIO50_DDR DDRF
#define DIO50_PWM nullptr
#define DIO51_PIN PINF5
#define DIO51_RPORT PINF
#define DIO51_WPORT PORTF
#define DIO51_DDR DDRF
#define DIO51_PWM nullptr
#define DIO52_PIN PINF6
#define DIO52_RPORT PINF
#define DIO52_WPORT PORTF
#define DIO52_DDR DDRF
#define DIO52_PWM nullptr
#define DIO53_PIN PINF7
#define DIO53_RPORT PINF
#define DIO53_WPORT PORTF
#define DIO53_DDR DDRF
#define DIO53_PWM nullptr
#undef PA0
#define PA0_PIN PINA0
#define PA0_RPORT PINA
#define PA0_WPORT PORTA
#define PA0_DDR DDRA
#define PA0_PWM nullptr
#undef PA1
#define PA1_PIN PINA1
#define PA1_RPORT PINA
#define PA1_WPORT PORTA
#define PA1_DDR DDRA
#define PA1_PWM nullptr
#undef PA2
#define PA2_PIN PINA2
#define PA2_RPORT PINA
#define PA2_WPORT PORTA
#define PA2_DDR DDRA
#define PA2_PWM nullptr
#undef PA3
#define PA3_PIN PINA3
#define PA3_RPORT PINA
#define PA3_WPORT PORTA
#define PA3_DDR DDRA
#define PA3_PWM nullptr
#undef PA4
#define PA4_PIN PINA4
#define PA4_RPORT PINA
#define PA4_WPORT PORTA
#define PA4_DDR DDRA
#define PA4_PWM nullptr
#undef PA5
#define PA5_PIN PINA5
#define PA5_RPORT PINA
#define PA5_WPORT PORTA
#define PA5_DDR DDRA
#define PA5_PWM nullptr
#undef PA6
#define PA6_PIN PINA6
#define PA6_RPORT PINA
#define PA6_WPORT PORTA
#define PA6_DDR DDRA
#define PA6_PWM nullptr
#undef PA7
#define PA7_PIN PINA7
#define PA7_RPORT PINA
#define PA7_WPORT PORTA
#define PA7_DDR DDRA
#define PA7_PWM nullptr
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_DDR DDRB
#define PB0_PWM nullptr
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_DDR DDRB
#define PB1_PWM nullptr
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_DDR DDRB
#define PB2_PWM nullptr
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_DDR DDRB
#define PB3_PWM nullptr
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_DDR DDRB
#define PB4_PWM &OCR2A
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_DDR DDRB
#define PB5_PWM nullptr
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_DDR DDRB
#define PB6_PWM nullptr
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_DDR DDRB
#define PB7_PWM &OCR0A
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_DDR DDRC
#define PC0_PWM nullptr
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_DDR DDRC
#define PC1_PWM nullptr
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_DDR DDRC
#define PC2_PWM nullptr
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_DDR DDRC
#define PC3_PWM nullptr
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_DDR DDRC
#define PC4_PWM nullptr
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_DDR DDRC
#define PC5_PWM nullptr
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_DDR DDRC
#define PC6_PWM nullptr
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_DDR DDRC
#define PC7_PWM nullptr
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_DDR DDRD
#define PD0_PWM nullptr
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_DDR DDRD
#define PD1_PWM nullptr
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_DDR DDRD
#define PD2_PWM nullptr
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_DDR DDRD
#define PD3_PWM nullptr
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_DDR DDRD
#define PD4_PWM nullptr
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_DDR DDRD
#define PD5_PWM nullptr
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_DDR DDRD
#define PD6_PWM nullptr
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_DDR DDRD
#define PD7_PWM nullptr
#undef PE0
#define PE0_PIN PINE0
#define PE0_RPORT PINE
#define PE0_WPORT PORTE
#define PE0_DDR DDRE
#define PE0_PWM nullptr
#undef PE1
#define PE1_PIN PINE1
#define PE1_RPORT PINE
#define PE1_WPORT PORTE
#define PE1_DDR DDRE
#define PE1_PWM nullptr
#undef PE2
#define PE2_PIN PINE2
#define PE2_RPORT PINE
#define PE2_WPORT PORTE
#define PE2_DDR DDRE
#define PE2_PWM nullptr
#undef PE3
#define PE3_PIN PINE3
#define PE3_RPORT PINE
#define PE3_WPORT PORTE
#define PE3_DDR DDRE
#define PE3_PWM &OCR3AL
#undef PE4
#define PE4_PIN PINE4
#define PE4_RPORT PINE
#define PE4_WPORT PORTE
#define PE4_DDR DDRE
#define PE4_PWM &OCR3BL
#undef PE5
#define PE5_PIN PINE5
#define PE5_RPORT PINE
#define PE5_WPORT PORTE
#define PE5_DDR DDRE
#define PE5_PWM &OCR3CL
#undef PE6
#define PE6_PIN PINE6
#define PE6_RPORT PINE
#define PE6_WPORT PORTE
#define PE6_DDR DDRE
#define PE6_PWM nullptr
#undef PE7
#define PE7_PIN PINE7
#define PE7_RPORT PINE
#define PE7_WPORT PORTE
#define PE7_DDR DDRE
#define PE7_PWM nullptr
#undef PF0
#define PF0_PIN PINF0
#define PF0_RPORT PINF
#define PF0_WPORT PORTF
#define PF0_DDR DDRF
#define PF0_PWM nullptr
#undef PF1
#define PF1_PIN PINF1
#define PF1_RPORT PINF
#define PF1_WPORT PORTF
#define PF1_DDR DDRF
#define PF1_PWM nullptr
#undef PF2
#define PF2_PIN PINF2
#define PF2_RPORT PINF
#define PF2_WPORT PORTF
#define PF2_DDR DDRF
#define PF2_PWM nullptr
#undef PF3
#define PF3_PIN PINF3
#define PF3_RPORT PINF
#define PF3_WPORT PORTF
#define PF3_DDR DDRF
#define PF3_PWM nullptr
#undef PF4
#define PF4_PIN PINF4
#define PF4_RPORT PINF
#define PF4_WPORT PORTF
#define PF4_DDR DDRF
#define PF4_PWM nullptr
#undef PF5
#define PF5_PIN PINF5
#define PF5_RPORT PINF
#define PF5_WPORT PORTF
#define PF5_DDR DDRF
#define PF5_PWM nullptr
#undef PF6
#define PF6_PIN PINF6
#define PF6_RPORT PINF
#define PF6_WPORT PORTF
#define PF6_DDR DDRF
#define PF6_PWM nullptr
#undef PF7
#define PF7_PIN PINF7
#define PF7_RPORT PINF
#define PF7_WPORT PORTF
#define PF7_DDR DDRF
#define PF7_PWM nullptr
#undef PG0
#define PG0_PIN PING0
#define PG0_RPORT PING
#define PG0_WPORT PORTG
#define PG0_DDR DDRG
#define PG0_PWM nullptr
#undef PG1
#define PG1_PIN PING1
#define PG1_RPORT PING
#define PG1_WPORT PORTG
#define PG1_DDR DDRG
#define PG1_PWM nullptr
#undef PG2
#define PG2_PIN PING2
#define PG2_RPORT PING
#define PG2_WPORT PORTG
#define PG2_DDR DDRG
#define PG2_PWM nullptr
#undef PG3
#define PG3_PIN PING3
#define PG3_RPORT PING
#define PG3_WPORT PORTG
#define PG3_DDR DDRG
#define PG3_PWM nullptr
#undef PG4
#define PG4_PIN PING4
#define PG4_RPORT PING
#define PG4_WPORT PORTG
#define PG4_DDR DDRG
#define PG4_PWM nullptr
#undef PG5
#define PG5_PIN PING5
#define PG5_RPORT PING
#define PG5_WPORT PORTG
#define PG5_DDR DDRG
#define PG5_PWM &OCR0B

View File

@ -0,0 +1,357 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Pin mapping for the 168, 328, and 328P
*
* Logical Pin: 08 09 10 11 12 13 14 15 16 17 18 19 20 21 00 01 02 03 04 05 06 07
* Port: B0 B1 B2 B3 B4 B5 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7
*/
#include "../fastio.h"
#define DEBUG_LED AIO5
// UART
#define RXD DIO0
#define TXD DIO1
// SPI
#define SCK DIO13
#define MISO DIO12
#define MOSI DIO11
#define SS DIO10
// TWI (I2C)
#define SCL AIO5
#define SDA AIO4
// Timers and PWM
#define OC0A DIO6
#define OC0B DIO5
#define OC1A DIO9
#define OC1B DIO10
#define OC2A DIO11
#define OC2B DIO3
// Digital I/O
#define DIO0_PIN PIND0
#define DIO0_RPORT PIND
#define DIO0_WPORT PORTD
#define DIO0_DDR DDRD
#define DIO0_PWM nullptr
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_DDR DDRD
#define DIO1_PWM nullptr
#define DIO2_PIN PIND2
#define DIO2_RPORT PIND
#define DIO2_WPORT PORTD
#define DIO2_DDR DDRD
#define DIO2_PWM nullptr
#define DIO3_PIN PIND3
#define DIO3_RPORT PIND
#define DIO3_WPORT PORTD
#define DIO3_DDR DDRD
#define DIO3_PWM &OCR2B
#define DIO4_PIN PIND4
#define DIO4_RPORT PIND
#define DIO4_WPORT PORTD
#define DIO4_DDR DDRD
#define DIO4_PWM nullptr
#define DIO5_PIN PIND5
#define DIO5_RPORT PIND
#define DIO5_WPORT PORTD
#define DIO5_DDR DDRD
#define DIO5_PWM &OCR0B
#define DIO6_PIN PIND6
#define DIO6_RPORT PIND
#define DIO6_WPORT PORTD
#define DIO6_DDR DDRD
#define DIO6_PWM &OCR0A
#define DIO7_PIN PIND7
#define DIO7_RPORT PIND
#define DIO7_WPORT PORTD
#define DIO7_DDR DDRD
#define DIO7_PWM nullptr
#define DIO8_PIN PINB0
#define DIO8_RPORT PINB
#define DIO8_WPORT PORTB
#define DIO8_DDR DDRB
#define DIO8_PWM nullptr
#define DIO9_PIN PINB1
#define DIO9_RPORT PINB
#define DIO9_WPORT PORTB
#define DIO9_DDR DDRB
#define DIO9_PWM nullptr
#define DIO10_PIN PINB2
#define DIO10_RPORT PINB
#define DIO10_WPORT PORTB
#define DIO10_DDR DDRB
#define DIO10_PWM nullptr
#define DIO11_PIN PINB3
#define DIO11_RPORT PINB
#define DIO11_WPORT PORTB
#define DIO11_DDR DDRB
#define DIO11_PWM &OCR2A
#define DIO12_PIN PINB4
#define DIO12_RPORT PINB
#define DIO12_WPORT PORTB
#define DIO12_DDR DDRB
#define DIO12_PWM nullptr
#define DIO13_PIN PINB5
#define DIO13_RPORT PINB
#define DIO13_WPORT PORTB
#define DIO13_DDR DDRB
#define DIO13_PWM nullptr
#define DIO14_PIN PINC0
#define DIO14_RPORT PINC
#define DIO14_WPORT PORTC
#define DIO14_DDR DDRC
#define DIO14_PWM nullptr
#define DIO15_PIN PINC1
#define DIO15_RPORT PINC
#define DIO15_WPORT PORTC
#define DIO15_DDR DDRC
#define DIO15_PWM nullptr
#define DIO16_PIN PINC2
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_DDR DDRC
#define DIO16_PWM nullptr
#define DIO17_PIN PINC3
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_DDR DDRC
#define DIO17_PWM nullptr
#define DIO18_PIN PINC4
#define DIO18_RPORT PINC
#define DIO18_WPORT PORTC
#define DIO18_DDR DDRC
#define DIO18_PWM nullptr
#define DIO19_PIN PINC5
#define DIO19_RPORT PINC
#define DIO19_WPORT PORTC
#define DIO19_DDR DDRC
#define DIO19_PWM nullptr
#define DIO20_PIN PINC6
#define DIO20_RPORT PINC
#define DIO20_WPORT PORTC
#define DIO20_DDR DDRC
#define DIO20_PWM nullptr
#define DIO21_PIN PINC7
#define DIO21_RPORT PINC
#define DIO21_WPORT PORTC
#define DIO21_DDR DDRC
#define DIO21_PWM nullptr
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_DDR DDRB
#define PB0_PWM nullptr
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_DDR DDRB
#define PB1_PWM nullptr
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_DDR DDRB
#define PB2_PWM nullptr
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_DDR DDRB
#define PB3_PWM &OCR2A
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_DDR DDRB
#define PB4_PWM nullptr
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_DDR DDRB
#define PB5_PWM nullptr
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_DDR DDRB
#define PB6_PWM nullptr
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_DDR DDRB
#define PB7_PWM nullptr
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_DDR DDRC
#define PC0_PWM nullptr
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_DDR DDRC
#define PC1_PWM nullptr
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_DDR DDRC
#define PC2_PWM nullptr
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_DDR DDRC
#define PC3_PWM nullptr
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_DDR DDRC
#define PC4_PWM nullptr
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_DDR DDRC
#define PC5_PWM nullptr
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_DDR DDRC
#define PC6_PWM nullptr
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_DDR DDRC
#define PC7_PWM nullptr
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_DDR DDRD
#define PD0_PWM nullptr
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_DDR DDRD
#define PD1_PWM nullptr
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_DDR DDRD
#define PD2_PWM nullptr
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_DDR DDRD
#define PD3_PWM &OCR2B
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_DDR DDRD
#define PD4_PWM nullptr
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_DDR DDRD
#define PD5_PWM &OCR0B
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_DDR DDRD
#define PD6_PWM &OCR0A
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_DDR DDRD
#define PD7_PWM nullptr

View File

@ -0,0 +1,552 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Pin mapping for the 644, 644p, 644pa, and 1284p
*
* Logical Pin: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
* Port: B0 B1 B2 B3 B4 B5 B6 B7 D0 D1 D2 D3 D4 D5 D6 D7 C0 C1 C2 C3 C4 C5 C6 C7 A7 A6 A5 A4 A3 A2 A1 A0
*/
/** ATMega644
*
* +---\/---+
* (D 0) PB0 1| |40 PA0 (AI 0 / D31)
* (D 1) PB1 2| |39 PA1 (AI 1 / D30)
* INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
* PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
* PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
* MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
* MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
* SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
* RST 9| |32 AREF
* VCC 10| |31 GND
* GND 11| |30 AVCC
* XTAL2 12| |29 PC7 (D 23)
* XTAL1 13| |28 PC6 (D 22)
* RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
* TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
* INT0 RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
* INT1 TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
* PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
* PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
* PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
* +--------+
*/
#include "../fastio.h"
#define DEBUG_LED DIO0
// UART
#define RXD DIO8
#define TXD DIO9
#define RXD0 DIO8
#define TXD0 DIO9
#define RXD1 DIO10
#define TXD1 DIO11
// SPI
#define SCK DIO7
#define MISO DIO6
#define MOSI DIO5
#define SS DIO4
// TWI (I2C)
#define SCL DIO16
#define SDA DIO17
// Timers and PWM
#define OC0A DIO3
#define OC0B DIO4
#define OC1A DIO13
#define OC1B DIO12
#define OC2A DIO15
#define OC2B DIO14
// Digital I/O
#define DIO0_PIN PINB0
#define DIO0_RPORT PINB
#define DIO0_WPORT PORTB
#define DIO0_DDR DDRB
#define DIO0_PWM nullptr
#define DIO1_PIN PINB1
#define DIO1_RPORT PINB
#define DIO1_WPORT PORTB
#define DIO1_DDR DDRB
#define DIO1_PWM nullptr
#define DIO2_PIN PINB2
#define DIO2_RPORT PINB
#define DIO2_WPORT PORTB
#define DIO2_DDR DDRB
#define DIO2_PWM nullptr
#define DIO3_PIN PINB3
#define DIO3_RPORT PINB
#define DIO3_WPORT PORTB
#define DIO3_DDR DDRB
#define DIO3_PWM &OCR0A
#define DIO4_PIN PINB4
#define DIO4_RPORT PINB
#define DIO4_WPORT PORTB
#define DIO4_DDR DDRB
#define DIO4_PWM &OCR0B
#define DIO5_PIN PINB5
#define DIO5_RPORT PINB
#define DIO5_WPORT PORTB
#define DIO5_DDR DDRB
#define DIO5_PWM nullptr
#define DIO6_PIN PINB6
#define DIO6_RPORT PINB
#define DIO6_WPORT PORTB
#define DIO6_DDR DDRB
#define DIO6_PWM nullptr
#define DIO7_PIN PINB7
#define DIO7_RPORT PINB
#define DIO7_WPORT PORTB
#define DIO7_DDR DDRB
#define DIO7_PWM nullptr
#define DIO8_PIN PIND0
#define DIO8_RPORT PIND
#define DIO8_WPORT PORTD
#define DIO8_DDR DDRD
#define DIO8_PWM nullptr
#define DIO9_PIN PIND1
#define DIO9_RPORT PIND
#define DIO9_WPORT PORTD
#define DIO9_DDR DDRD
#define DIO9_PWM nullptr
#define DIO10_PIN PIND2
#define DIO10_RPORT PIND
#define DIO10_WPORT PORTD
#define DIO10_DDR DDRD
#define DIO10_PWM nullptr
#define DIO11_PIN PIND3
#define DIO11_RPORT PIND
#define DIO11_WPORT PORTD
#define DIO11_DDR DDRD
#define DIO11_PWM nullptr
#define DIO12_PIN PIND4
#define DIO12_RPORT PIND
#define DIO12_WPORT PORTD
#define DIO12_DDR DDRD
#define DIO12_PWM &OCR1B
#define DIO13_PIN PIND5
#define DIO13_RPORT PIND
#define DIO13_WPORT PORTD
#define DIO13_DDR DDRD
#define DIO13_PWM &OCR1A
#define DIO14_PIN PIND6
#define DIO14_RPORT PIND
#define DIO14_WPORT PORTD
#define DIO14_DDR DDRD
#define DIO14_PWM &OCR2B
#define DIO15_PIN PIND7
#define DIO15_RPORT PIND
#define DIO15_WPORT PORTD
#define DIO15_DDR DDRD
#define DIO15_PWM &OCR2A
#define DIO16_PIN PINC0
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_DDR DDRC
#define DIO16_PWM nullptr
#define DIO17_PIN PINC1
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_DDR DDRC
#define DIO17_PWM nullptr
#define DIO18_PIN PINC2
#define DIO18_RPORT PINC
#define DIO18_WPORT PORTC
#define DIO18_DDR DDRC
#define DIO18_PWM nullptr
#define DIO19_PIN PINC3
#define DIO19_RPORT PINC
#define DIO19_WPORT PORTC
#define DIO19_DDR DDRC
#define DIO19_PWM nullptr
#define DIO20_PIN PINC4
#define DIO20_RPORT PINC
#define DIO20_WPORT PORTC
#define DIO20_DDR DDRC
#define DIO20_PWM nullptr
#define DIO21_PIN PINC5
#define DIO21_RPORT PINC
#define DIO21_WPORT PORTC
#define DIO21_DDR DDRC
#define DIO21_PWM nullptr
#define DIO22_PIN PINC6
#define DIO22_RPORT PINC
#define DIO22_WPORT PORTC
#define DIO22_DDR DDRC
#define DIO22_PWM nullptr
#define DIO23_PIN PINC7
#define DIO23_RPORT PINC
#define DIO23_WPORT PORTC
#define DIO23_DDR DDRC
#define DIO23_PWM nullptr
#define DIO24_PIN PINA7
#define DIO24_RPORT PINA
#define DIO24_WPORT PORTA
#define DIO24_DDR DDRA
#define DIO24_PWM nullptr
#define DIO25_PIN PINA6
#define DIO25_RPORT PINA
#define DIO25_WPORT PORTA
#define DIO25_DDR DDRA
#define DIO25_PWM nullptr
#define DIO26_PIN PINA5
#define DIO26_RPORT PINA
#define DIO26_WPORT PORTA
#define DIO26_DDR DDRA
#define DIO26_PWM nullptr
#define DIO27_PIN PINA4
#define DIO27_RPORT PINA
#define DIO27_WPORT PORTA
#define DIO27_DDR DDRA
#define DIO27_PWM nullptr
#define DIO28_PIN PINA3
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_DDR DDRA
#define DIO28_PWM nullptr
#define DIO29_PIN PINA2
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_DDR DDRA
#define DIO29_PWM nullptr
#define DIO30_PIN PINA1
#define DIO30_RPORT PINA
#define DIO30_WPORT PORTA
#define DIO30_DDR DDRA
#define DIO30_PWM nullptr
#define DIO31_PIN PINA0
#define DIO31_RPORT PINA
#define DIO31_WPORT PORTA
#define DIO31_DDR DDRA
#define DIO31_PWM nullptr
#define AIO0_PIN PINA0
#define AIO0_RPORT PINA
#define AIO0_WPORT PORTA
#define AIO0_DDR DDRA
#define AIO0_PWM nullptr
#define AIO1_PIN PINA1
#define AIO1_RPORT PINA
#define AIO1_WPORT PORTA
#define AIO1_DDR DDRA
#define AIO1_PWM nullptr
#define AIO2_PIN PINA2
#define AIO2_RPORT PINA
#define AIO2_WPORT PORTA
#define AIO2_DDR DDRA
#define AIO2_PWM nullptr
#define AIO3_PIN PINA3
#define AIO3_RPORT PINA
#define AIO3_WPORT PORTA
#define AIO3_DDR DDRA
#define AIO3_PWM nullptr
#define AIO4_PIN PINA4
#define AIO4_RPORT PINA
#define AIO4_WPORT PORTA
#define AIO4_DDR DDRA
#define AIO4_PWM nullptr
#define AIO5_PIN PINA5
#define AIO5_RPORT PINA
#define AIO5_WPORT PORTA
#define AIO5_DDR DDRA
#define AIO5_PWM nullptr
#define AIO6_PIN PINA6
#define AIO6_RPORT PINA
#define AIO6_WPORT PORTA
#define AIO6_DDR DDRA
#define AIO6_PWM nullptr
#define AIO7_PIN PINA7
#define AIO7_RPORT PINA
#define AIO7_WPORT PORTA
#define AIO7_DDR DDRA
#define AIO7_PWM nullptr
#undef PA0
#define PA0_PIN PINA0
#define PA0_RPORT PINA
#define PA0_WPORT PORTA
#define PA0_DDR DDRA
#define PA0_PWM nullptr
#undef PA1
#define PA1_PIN PINA1
#define PA1_RPORT PINA
#define PA1_WPORT PORTA
#define PA1_DDR DDRA
#define PA1_PWM nullptr
#undef PA2
#define PA2_PIN PINA2
#define PA2_RPORT PINA
#define PA2_WPORT PORTA
#define PA2_DDR DDRA
#define PA2_PWM nullptr
#undef PA3
#define PA3_PIN PINA3
#define PA3_RPORT PINA
#define PA3_WPORT PORTA
#define PA3_DDR DDRA
#define PA3_PWM nullptr
#undef PA4
#define PA4_PIN PINA4
#define PA4_RPORT PINA
#define PA4_WPORT PORTA
#define PA4_DDR DDRA
#define PA4_PWM nullptr
#undef PA5
#define PA5_PIN PINA5
#define PA5_RPORT PINA
#define PA5_WPORT PORTA
#define PA5_DDR DDRA
#define PA5_PWM nullptr
#undef PA6
#define PA6_PIN PINA6
#define PA6_RPORT PINA
#define PA6_WPORT PORTA
#define PA6_DDR DDRA
#define PA6_PWM nullptr
#undef PA7
#define PA7_PIN PINA7
#define PA7_RPORT PINA
#define PA7_WPORT PORTA
#define PA7_DDR DDRA
#define PA7_PWM nullptr
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_DDR DDRB
#define PB0_PWM nullptr
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_DDR DDRB
#define PB1_PWM nullptr
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_DDR DDRB
#define PB2_PWM nullptr
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_DDR DDRB
#define PB3_PWM &OCR0A
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_DDR DDRB
#define PB4_PWM &OCR0B
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_DDR DDRB
#define PB5_PWM nullptr
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_DDR DDRB
#define PB6_PWM nullptr
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_DDR DDRB
#define PB7_PWM nullptr
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_DDR DDRC
#define PC0_PWM nullptr
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_DDR DDRC
#define PC1_PWM nullptr
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_DDR DDRC
#define PC2_PWM nullptr
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_DDR DDRC
#define PC3_PWM nullptr
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_DDR DDRC
#define PC4_PWM nullptr
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_DDR DDRC
#define PC5_PWM nullptr
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_DDR DDRC
#define PC6_PWM nullptr
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_DDR DDRC
#define PC7_PWM nullptr
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_DDR DDRD
#define PD0_PWM nullptr
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_DDR DDRD
#define PD1_PWM nullptr
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_DDR DDRD
#define PD2_PWM nullptr
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_DDR DDRD
#define PD3_PWM nullptr
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_DDR DDRD
#define PD4_PWM nullptr
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_DDR DDRD
#define PD5_PWM nullptr
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_DDR DDRD
#define PD6_PWM &OCR2B
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_DDR DDRD
#define PD7_PWM &OCR2A

View File

@ -0,0 +1,697 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Pin mapping (Teensy) for AT90USB646, 647, 1286, and 1287
*
* Logical Pin: 28 29 30 31 32 33 34 35 20 21 22 23 24 25 26 27 10 11 12 13 14 15 16 17 00 01 02 03 04 05 06 07 08 09(46*47)36 37 18 19 38 39 40 41 42 43 44 45
* Port: A0 A1 A2 A3 A4 A5 A6 A7 B0 B1 B2 B3 B4 B5 B6 B7 C0 C1 C2 C3 C4 C5 C6 C7 D0 D1 D2 D3 D4 D5 D6 D7 E0 E1 E2 E3 E4 E5 E6 E7 F0 F1 F2 F3 F4 F5 F6 F7
* The logical pins 46 and 47 are not supported by Teensyduino, but are supported below as E2 and E3
*/
#include "../fastio.h"
// change for your board
#define DEBUG_LED DIO31 /* led D5 red */
// SPI
#define SCK DIO21 // 9
#define MISO DIO23 // 11
#define MOSI DIO22 // 10
#define SS DIO20 // 8
// Digital I/O
#define DIO0_PIN PIND0
#define DIO0_RPORT PIND
#define DIO0_WPORT PORTD
#define DIO0_PWM 0
#define DIO0_DDR DDRD
#define DIO1_PIN PIND1
#define DIO1_RPORT PIND
#define DIO1_WPORT PORTD
#define DIO1_PWM 0
#define DIO1_DDR DDRD
#define DIO2_PIN PIND2
#define DIO2_RPORT PIND
#define DIO2_WPORT PORTD
#define DIO2_PWM 0
#define DIO2_DDR DDRD
#define DIO3_PIN PIND3
#define DIO3_RPORT PIND
#define DIO3_WPORT PORTD
#define DIO3_PWM 0
#define DIO3_DDR DDRD
#define DIO4_PIN PIND4
#define DIO4_RPORT PIND
#define DIO4_WPORT PORTD
#define DIO4_PWM 0
#define DIO4_DDR DDRD
#define DIO5_PIN PIND5
#define DIO5_RPORT PIND
#define DIO5_WPORT PORTD
#define DIO5_PWM 0
#define DIO5_DDR DDRD
#define DIO6_PIN PIND6
#define DIO6_RPORT PIND
#define DIO6_WPORT PORTD
#define DIO6_PWM 0
#define DIO6_DDR DDRD
#define DIO7_PIN PIND7
#define DIO7_RPORT PIND
#define DIO7_WPORT PORTD
#define DIO7_PWM 0
#define DIO7_DDR DDRD
#define DIO8_PIN PINE0
#define DIO8_RPORT PINE
#define DIO8_WPORT PORTE
#define DIO8_PWM 0
#define DIO8_DDR DDRE
#define DIO9_PIN PINE1
#define DIO9_RPORT PINE
#define DIO9_WPORT PORTE
#define DIO9_PWM 0
#define DIO9_DDR DDRE
#define DIO10_PIN PINC0
#define DIO10_RPORT PINC
#define DIO10_WPORT PORTC
#define DIO10_PWM 0
#define DIO10_DDR DDRC
#define DIO11_PIN PINC1
#define DIO11_RPORT PINC
#define DIO11_WPORT PORTC
#define DIO11_PWM 0
#define DIO11_DDR DDRC
#define DIO12_PIN PINC2
#define DIO12_RPORT PINC
#define DIO12_WPORT PORTC
#define DIO12_PWM 0
#define DIO12_DDR DDRC
#define DIO13_PIN PINC3
#define DIO13_RPORT PINC
#define DIO13_WPORT PORTC
#define DIO13_PWM 0
#define DIO13_DDR DDRC
#define DIO14_PIN PINC4
#define DIO14_RPORT PINC
#define DIO14_WPORT PORTC
#define DIO14_PWM 0 // OC3C
#define DIO14_DDR DDRC
#define DIO15_PIN PINC5
#define DIO15_RPORT PINC
#define DIO15_WPORT PORTC
#define DIO15_PWM 0 // OC3B
#define DIO15_DDR DDRC
#define DIO16_PIN PINC6
#define DIO16_RPORT PINC
#define DIO16_WPORT PORTC
#define DIO16_PWM 0 // OC3A
#define DIO16_DDR DDRC
#define DIO17_PIN PINC7
#define DIO17_RPORT PINC
#define DIO17_WPORT PORTC
#define DIO17_PWM 0
#define DIO17_DDR DDRC
#define DIO18_PIN PINE6
#define DIO18_RPORT PINE
#define DIO18_WPORT PORTE
#define DIO18_PWM 0
#define DIO18_DDR DDRE
#define DIO19_PIN PINE7
#define DIO19_RPORT PINE
#define DIO19_WPORT PORTE
#define DIO19_PWM 0
#define DIO19_DDR DDRE
#define DIO20_PIN PINB0
#define DIO20_RPORT PINB
#define DIO20_WPORT PORTB
#define DIO20_PWM 0
#define DIO20_DDR DDRB
#define DIO21_PIN PINB1
#define DIO21_RPORT PINB
#define DIO21_WPORT PORTB
#define DIO21_PWM 0
#define DIO21_DDR DDRB
#define DIO22_PIN PINB2
#define DIO22_RPORT PINB
#define DIO22_WPORT PORTB
#define DIO22_PWM 0
#define DIO22_DDR DDRB
#define DIO23_PIN PINB3
#define DIO23_RPORT PINB
#define DIO23_WPORT PORTB
#define DIO23_PWM 0
#define DIO23_DDR DDRB
#define DIO24_PIN PINB4
#define DIO24_RPORT PINB
#define DIO24_WPORT PORTB
#define DIO24_PWM 0 // OC2A
#define DIO24_DDR DDRB
#define DIO25_PIN PINB5
#define DIO25_RPORT PINB
#define DIO25_WPORT PORTB
#define DIO25_PWM 0 // OC1A
#define DIO25_DDR DDRB
#define DIO26_PIN PINB6
#define DIO26_RPORT PINB
#define DIO26_WPORT PORTB
#define DIO26_PWM 0 // OC1B
#define DIO26_DDR DDRB
#define DIO27_PIN PINB7
#define DIO27_RPORT PINB
#define DIO27_WPORT PORTB
#define DIO27_PWM 0 // OC1C
#define DIO27_DDR DDRB
#define DIO28_PIN PINA0
#define DIO28_RPORT PINA
#define DIO28_WPORT PORTA
#define DIO28_PWM 0
#define DIO28_DDR DDRA
#define DIO29_PIN PINA1
#define DIO29_RPORT PINA
#define DIO29_WPORT PORTA
#define DIO29_PWM 0
#define DIO29_DDR DDRA
#define DIO30_PIN PINA2
#define DIO30_RPORT PINA
#define DIO30_WPORT PORTA
#define DIO30_PWM 0
#define DIO30_DDR DDRA
#define DIO31_PIN PINA3
#define DIO31_RPORT PINA
#define DIO31_WPORT PORTA
#define DIO31_PWM 0
#define DIO31_DDR DDRA
#define DIO32_PIN PINA4
#define DIO32_RPORT PINA
#define DIO32_WPORT PORTA
#define DIO32_PWM 0
#define DIO32_DDR DDRA
#define DIO33_PIN PINA5
#define DIO33_RPORT PINA
#define DIO33_WPORT PORTA
#define DIO33_PWM 0
#define DIO33_DDR DDRA
#define DIO34_PIN PINA6
#define DIO34_RPORT PINA
#define DIO34_WPORT PORTA
#define DIO34_PWM 0
#define DIO34_DDR DDRA
#define DIO35_PIN PINA7
#define DIO35_RPORT PINA
#define DIO35_WPORT PORTA
#define DIO35_PWM 0
#define DIO35_DDR DDRA
#define DIO36_PIN PINE4
#define DIO36_RPORT PINE
#define DIO36_WPORT PORTE
#define DIO36_PWM 0
#define DIO36_DDR DDRE
#define DIO37_PIN PINE5
#define DIO37_RPORT PINE
#define DIO37_WPORT PORTE
#define DIO37_PWM 0
#define DIO37_DDR DDRE
#define DIO38_PIN PINF0
#define DIO38_RPORT PINF
#define DIO38_WPORT PORTF
#define DIO38_PWM 0
#define DIO38_DDR DDRF
#define DIO39_PIN PINF1
#define DIO39_RPORT PINF
#define DIO39_WPORT PORTF
#define DIO39_PWM 0
#define DIO39_DDR DDRF
#define DIO40_PIN PINF2
#define DIO40_RPORT PINF
#define DIO40_WPORT PORTF
#define DIO40_PWM 0
#define DIO40_DDR DDRF
#define DIO41_PIN PINF3
#define DIO41_RPORT PINF
#define DIO41_WPORT PORTF
#define DIO41_PWM 0
#define DIO41_DDR DDRF
#define DIO42_PIN PINF4
#define DIO42_RPORT PINF
#define DIO42_WPORT PORTF
#define DIO42_PWM 0
#define DIO42_DDR DDRF
#define DIO43_PIN PINF5
#define DIO43_RPORT PINF
#define DIO43_WPORT PORTF
#define DIO43_PWM 0
#define DIO43_DDR DDRF
#define DIO44_PIN PINF6
#define DIO44_RPORT PINF
#define DIO44_WPORT PORTF
#define DIO44_PWM 0
#define DIO44_DDR DDRF
#define DIO45_PIN PINF7
#define DIO45_RPORT PINF
#define DIO45_WPORT PORTF
#define DIO45_PWM 0
#define DIO45_DDR DDRF
#define AIO0_PIN PINF0
#define AIO0_RPORT PINF
#define AIO0_WPORT PORTF
#define AIO0_PWM 0
#define AIO0_DDR DDRF
#define AIO1_PIN PINF1
#define AIO1_RPORT PINF
#define AIO1_WPORT PORTF
#define AIO1_PWM 0
#define AIO1_DDR DDRF
#define AIO2_PIN PINF2
#define AIO2_RPORT PINF
#define AIO2_WPORT PORTF
#define AIO2_PWM 0
#define AIO2_DDR DDRF
#define AIO3_PIN PINF3
#define AIO3_RPORT PINF
#define AIO3_WPORT PORTF
#define AIO3_PWM 0
#define AIO3_DDR DDRF
#define AIO4_PIN PINF4
#define AIO4_RPORT PINF
#define AIO4_WPORT PORTF
#define AIO4_PWM 0
#define AIO4_DDR DDRF
#define AIO5_PIN PINF5
#define AIO5_RPORT PINF
#define AIO5_WPORT PORTF
#define AIO5_PWM 0
#define AIO5_DDR DDRF
#define AIO6_PIN PINF6
#define AIO6_RPORT PINF
#define AIO6_WPORT PORTF
#define AIO6_PWM 0
#define AIO6_DDR DDRF
#define AIO7_PIN PINF7
#define AIO7_RPORT PINF
#define AIO7_WPORT PORTF
#define AIO7_PWM 0
#define AIO7_DDR DDRF
//-- Begin not supported by Teensyduino
//-- don't use Arduino functions on these pins pinMode/digitalWrite/etc
#define DIO46_PIN PINE2
#define DIO46_RPORT PINE
#define DIO46_WPORT PORTE
#define DIO46_PWM 0
#define DIO46_DDR DDRE
#define DIO47_PIN PINE3
#define DIO47_RPORT PINE
#define DIO47_WPORT PORTE
#define DIO47_PWM 0
#define DIO47_DDR DDRE
#define TEENSY_E2 46
#define TEENSY_E3 47
//-- end not supported by Teensyduino
#undef PA0
#define PA0_PIN PINA0
#define PA0_RPORT PINA
#define PA0_WPORT PORTA
#define PA0_PWM 0
#define PA0_DDR DDRA
#undef PA1
#define PA1_PIN PINA1
#define PA1_RPORT PINA
#define PA1_WPORT PORTA
#define PA1_PWM 0
#define PA1_DDR DDRA
#undef PA2
#define PA2_PIN PINA2
#define PA2_RPORT PINA
#define PA2_WPORT PORTA
#define PA2_PWM 0
#define PA2_DDR DDRA
#undef PA3
#define PA3_PIN PINA3
#define PA3_RPORT PINA
#define PA3_WPORT PORTA
#define PA3_PWM 0
#define PA3_DDR DDRA
#undef PA4
#define PA4_PIN PINA4
#define PA4_RPORT PINA
#define PA4_WPORT PORTA
#define PA4_PWM 0
#define PA4_DDR DDRA
#undef PA5
#define PA5_PIN PINA5
#define PA5_RPORT PINA
#define PA5_WPORT PORTA
#define PA5_PWM 0
#define PA5_DDR DDRA
#undef PA6
#define PA6_PIN PINA6
#define PA6_RPORT PINA
#define PA6_WPORT PORTA
#define PA6_PWM 0
#define PA6_DDR DDRA
#undef PA7
#define PA7_PIN PINA7
#define PA7_RPORT PINA
#define PA7_WPORT PORTA
#define PA7_PWM 0
#define PA7_DDR DDRA
#undef PB0
#define PB0_PIN PINB0
#define PB0_RPORT PINB
#define PB0_WPORT PORTB
#define PB0_PWM 0
#define PB0_DDR DDRB
#undef PB1
#define PB1_PIN PINB1
#define PB1_RPORT PINB
#define PB1_WPORT PORTB
#define PB1_PWM 0
#define PB1_DDR DDRB
#undef PB2
#define PB2_PIN PINB2
#define PB2_RPORT PINB
#define PB2_WPORT PORTB
#define PB2_PWM 0
#define PB2_DDR DDRB
#undef PB3
#define PB3_PIN PINB3
#define PB3_RPORT PINB
#define PB3_WPORT PORTB
#define PB3_PWM 0
#define PB3_DDR DDRB
#undef PB4
#define PB4_PIN PINB4
#define PB4_RPORT PINB
#define PB4_WPORT PORTB
#define PB4_PWM 0
#define PB4_DDR DDRB
#undef PB5
#define PB5_PIN PINB5
#define PB5_RPORT PINB
#define PB5_WPORT PORTB
#define PB5_PWM 0
#define PB5_DDR DDRB
#undef PB6
#define PB6_PIN PINB6
#define PB6_RPORT PINB
#define PB6_WPORT PORTB
#define PB6_PWM 0
#define PB6_DDR DDRB
#undef PB7
#define PB7_PIN PINB7
#define PB7_RPORT PINB
#define PB7_WPORT PORTB
#define PB7_PWM 0
#define PB7_DDR DDRB
#undef PC0
#define PC0_PIN PINC0
#define PC0_RPORT PINC
#define PC0_WPORT PORTC
#define PC0_PWM 0
#define PC0_DDR DDRC
#undef PC1
#define PC1_PIN PINC1
#define PC1_RPORT PINC
#define PC1_WPORT PORTC
#define PC1_PWM 0
#define PC1_DDR DDRC
#undef PC2
#define PC2_PIN PINC2
#define PC2_RPORT PINC
#define PC2_WPORT PORTC
#define PC2_PWM 0
#define PC2_DDR DDRC
#undef PC3
#define PC3_PIN PINC3
#define PC3_RPORT PINC
#define PC3_WPORT PORTC
#define PC3_PWM 0
#define PC3_DDR DDRC
#undef PC4
#define PC4_PIN PINC4
#define PC4_RPORT PINC
#define PC4_WPORT PORTC
#define PC4_PWM 0
#define PC4_DDR DDRC
#undef PC5
#define PC5_PIN PINC5
#define PC5_RPORT PINC
#define PC5_WPORT PORTC
#define PC5_PWM 0
#define PC5_DDR DDRC
#undef PC6
#define PC6_PIN PINC6
#define PC6_RPORT PINC
#define PC6_WPORT PORTC
#define PC6_PWM 0
#define PC6_DDR DDRC
#undef PC7
#define PC7_PIN PINC7
#define PC7_RPORT PINC
#define PC7_WPORT PORTC
#define PC7_PWM 0
#define PC7_DDR DDRC
#undef PD0
#define PD0_PIN PIND0
#define PD0_RPORT PIND
#define PD0_WPORT PORTD
#define PD0_PWM 0 // OC0B
#define PD0_DDR DDRD
#undef PD1
#define PD1_PIN PIND1
#define PD1_RPORT PIND
#define PD1_WPORT PORTD
#define PD1_PWM 0 // OC2B
#define PD1_DDR DDRD
#undef PD2
#define PD2_PIN PIND2
#define PD2_RPORT PIND
#define PD2_WPORT PORTD
#define PD2_PWM 0
#define PD2_DDR DDRD
#undef PD3
#define PD3_PIN PIND3
#define PD3_RPORT PIND
#define PD3_WPORT PORTD
#define PD3_PWM 0
#define PD3_DDR DDRD
#undef PD4
#define PD4_PIN PIND4
#define PD4_RPORT PIND
#define PD4_WPORT PORTD
#define PD4_PWM 0
#define PD4_DDR DDRD
#undef PD5
#define PD5_PIN PIND5
#define PD5_RPORT PIND
#define PD5_WPORT PORTD
#define PD5_PWM 0
#define PD5_DDR DDRD
#undef PD6
#define PD6_PIN PIND6
#define PD6_RPORT PIND
#define PD6_WPORT PORTD
#define PD6_PWM 0
#define PD6_DDR DDRD
#undef PD7
#define PD7_PIN PIND7
#define PD7_RPORT PIND
#define PD7_WPORT PORTD
#define PD7_PWM 0
#define PD7_DDR DDRD
#undef PE0
#define PE0_PIN PINE0
#define PE0_RPORT PINE
#define PE0_WPORT PORTE
#define PE0_PWM 0
#define PE0_DDR DDRE
#undef PE1
#define PE1_PIN PINE1
#define PE1_RPORT PINE
#define PE1_WPORT PORTE
#define PE1_PWM 0
#define PE1_DDR DDRE
#undef PE2
#define PE2_PIN PINE2
#define PE2_RPORT PINE
#define PE2_WPORT PORTE
#define PE2_PWM 0
#define PE2_DDR DDRE
#undef PE3
#define PE3_PIN PINE3
#define PE3_RPORT PINE
#define PE3_WPORT PORTE
#define PE3_PWM 0
#define PE3_DDR DDRE
#undef PE4
#define PE4_PIN PINE4
#define PE4_RPORT PINE
#define PE4_WPORT PORTE
#define PE4_PWM 0
#define PE4_DDR DDRE
#undef PE5
#define PE5_PIN PINE5
#define PE5_RPORT PINE
#define PE5_WPORT PORTE
#define PE5_PWM 0
#define PE5_DDR DDRE
#undef PE6
#define PE6_PIN PINE6
#define PE6_RPORT PINE
#define PE6_WPORT PORTE
#define PE6_PWM 0
#define PE6_DDR DDRE
#undef PE7
#define PE7_PIN PINE7
#define PE7_RPORT PINE
#define PE7_WPORT PORTE
#define PE7_PWM 0
#define PE7_DDR DDRE
#undef PF0
#define PF0_PIN PINF0
#define PF0_RPORT PINF
#define PF0_WPORT PORTF
#define PF0_PWM 0
#define PF0_DDR DDRF
#undef PF1
#define PF1_PIN PINF1
#define PF1_RPORT PINF
#define PF1_WPORT PORTF
#define PF1_PWM 0
#define PF1_DDR DDRF
#undef PF2
#define PF2_PIN PINF2
#define PF2_RPORT PINF
#define PF2_WPORT PORTF
#define PF2_PWM 0
#define PF2_DDR DDRF
#undef PF3
#define PF3_PIN PINF3
#define PF3_RPORT PINF
#define PF3_WPORT PORTF
#define PF3_PWM 0
#define PF3_DDR DDRF
#undef PF4
#define PF4_PIN PINF4
#define PF4_RPORT PINF
#define PF4_WPORT PORTF
#define PF4_PWM 0
#define PF4_DDR DDRF
#undef PF5
#define PF5_PIN PINF5
#define PF5_RPORT PINF
#define PF5_WPORT PORTF
#define PF5_PWM 0
#define PF5_DDR DDRF
#undef PF6
#define PF6_PIN PINF6
#define PF6_RPORT PINF
#define PF6_WPORT PORTF
#define PF6_PWM 0
#define PF6_DDR DDRF
#undef PF7
#define PF7_PIN PINF7
#define PF7_RPORT PINF
#define PF7_WPORT PORTF
#define PF7_PWM 0
#define PF7_DDR DDRF
/**
* Some of the pin mapping functions of the Teensduino extension to the Arduino IDE
* do not function the same as the other Arduino extensions.
*/
//digitalPinToTimer(pin) function works like Arduino but Timers are not defined
#define TIMER0B 1
#define TIMER1A 7
#define TIMER1B 8
#define TIMER1C 9
#define TIMER2A 6
#define TIMER2B 2
#define TIMER3A 5
#define TIMER3B 4
#define TIMER3C 3

View File

@ -0,0 +1,26 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#if HAS_SPI_TFT || HAS_FSMC_TFT
#error "Sorry! TFT displays are not available for HAL/AVR."
#endif

View File

@ -0,0 +1,22 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once

View File

@ -0,0 +1,22 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once

View File

@ -0,0 +1,101 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Test AVR-specific configuration values for errors at compile-time.
*/
/**
* Check for common serial pin conflicts
*/
#define CHECK_SERIAL_PIN(N) ( \
X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \
|| X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \
|| X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \
|| X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \
|| X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \
|| X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \
)
#if CONF_SERIAL_IS(0) // D0-D1. No known conflicts.
#endif
#if CONF_SERIAL_IS(1) && (CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19))
#error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board."
#endif
#if CONF_SERIAL_IS(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17))
#error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board."
#endif
#if CONF_SERIAL_IS(3) && (CHECK_SERIAL_PIN(14) || CHECK_SERIAL_PIN(15))
#error "Serial Port 3 pin D14 and/or D15 conflicts with another pin on the board."
#endif
#undef CHECK_SERIAL_PIN
/**
* Checks for FAST PWM
*/
#if ALL(FAST_PWM_FAN, USE_OCR2A_AS_TOP, HAS_TCCR2)
#error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2."
#endif
/**
* Checks for SOFT PWM
*/
#if HAS_FAN0 && FAN_PIN == 9 && DISABLED(FAN_SOFT_PWM) && ENABLED(SPEAKER)
#error "FAN_PIN 9 Hardware PWM uses Timer 2 which conflicts with Arduino AVR Tone Timer (for SPEAKER)."
#error "Disable SPEAKER or enable FAN_SOFT_PWM."
#endif
/**
* Sanity checks for Spindle / Laser PWM
*/
#if ENABLED(SPINDLE_LASER_USE_PWM)
#include "../ServoTimers.h" // Needed to check timer availability (_useTimer3)
#if SPINDLE_LASER_PWM_PIN == 4 || WITHIN(SPINDLE_LASER_PWM_PIN, 11, 13)
#error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by a system interrupt."
#elif NUM_SERVOS > 0 && defined(_useTimer3) && (WITHIN(SPINDLE_LASER_PWM_PIN, 2, 3) || SPINDLE_LASER_PWM_PIN == 5)
#error "Counter/Timer for SPINDLE_LASER_PWM_PIN is used by the servo system."
#endif
#elif SPINDLE_LASER_FREQUENCY
#error "SPINDLE_LASER_FREQUENCY requires SPINDLE_LASER_USE_PWM."
#endif
/**
* The Trinamic library includes SoftwareSerial.h, leading to a compile error.
*/
#if BOTH(HAS_TRINAMIC_CONFIG, ENDSTOP_INTERRUPTS_FEATURE)
#error "TMCStepper includes SoftwareSerial.h which is incompatible with ENDSTOP_INTERRUPTS_FEATURE. Disable ENDSTOP_INTERRUPTS_FEATURE to continue."
#endif
#if BOTH(HAS_TMC_SW_SERIAL, MONITOR_DRIVER_STATUS)
#error "MONITOR_DRIVER_STATUS causes performance issues when used with SoftwareSerial-connected drivers. Disable MONITOR_DRIVER_STATUS or use hardware serial to continue."
#endif
/**
* Postmortem debugging
*/
#if ENABLED(POSTMORTEM_DEBUGGING)
#error "POSTMORTEM_DEBUGGING is not supported on AVR boards."
#endif
#if USING_PULLDOWNS
#error "PULLDOWN pin mode is not available on AVR boards."
#endif

113
src/HAL/AVR/math.h Normal file
View File

@ -0,0 +1,113 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Optimized math functions for AVR
*/
// intRes = longIn1 * longIn2 >> 24
// uses:
// A[tmp] to store 0
// B[tmp] to store bits 16-23 of the 48bit result. The top bit is used to round the two byte result.
// note that the lower two bytes and the upper byte of the 48bit result are not calculated.
// this can cause the result to be out by one as the lower bytes may cause carries into the upper ones.
// B A are bits 24-39 and are the returned value
// C B A is longIn1
// D C B A is longIn2
//
FORCE_INLINE static uint16_t MultiU24X32toH16(uint32_t longIn1, uint32_t longIn2) {
uint8_t tmp1;
uint8_t tmp2;
uint16_t intRes;
__asm__ __volatile__(
A("clr %[tmp1]")
A("mul %A[longIn1], %B[longIn2]")
A("mov %[tmp2], r1")
A("mul %B[longIn1], %C[longIn2]")
A("movw %A[intRes], r0")
A("mul %C[longIn1], %C[longIn2]")
A("add %B[intRes], r0")
A("mul %C[longIn1], %B[longIn2]")
A("add %A[intRes], r0")
A("adc %B[intRes], r1")
A("mul %A[longIn1], %C[longIn2]")
A("add %[tmp2], r0")
A("adc %A[intRes], r1")
A("adc %B[intRes], %[tmp1]")
A("mul %B[longIn1], %B[longIn2]")
A("add %[tmp2], r0")
A("adc %A[intRes], r1")
A("adc %B[intRes], %[tmp1]")
A("mul %C[longIn1], %A[longIn2]")
A("add %[tmp2], r0")
A("adc %A[intRes], r1")
A("adc %B[intRes], %[tmp1]")
A("mul %B[longIn1], %A[longIn2]")
A("add %[tmp2], r1")
A("adc %A[intRes], %[tmp1]")
A("adc %B[intRes], %[tmp1]")
A("lsr %[tmp2]")
A("adc %A[intRes], %[tmp1]")
A("adc %B[intRes], %[tmp1]")
A("mul %D[longIn2], %A[longIn1]")
A("add %A[intRes], r0")
A("adc %B[intRes], r1")
A("mul %D[longIn2], %B[longIn1]")
A("add %B[intRes], r0")
A("clr r1")
: [intRes] "=&r" (intRes),
[tmp1] "=&r" (tmp1),
[tmp2] "=&r" (tmp2)
: [longIn1] "d" (longIn1),
[longIn2] "d" (longIn2)
: "cc"
);
return intRes;
}
// intRes = intIn1 * intIn2 >> 16
// uses:
// r26 to store 0
// r27 to store the byte 1 of the 24 bit result
FORCE_INLINE static uint16_t MultiU16X8toH16(uint8_t charIn1, uint16_t intIn2) {
uint8_t tmp;
uint16_t intRes;
__asm__ __volatile__ (
A("clr %[tmp]")
A("mul %[charIn1], %B[intIn2]")
A("movw %A[intRes], r0")
A("mul %[charIn1], %A[intIn2]")
A("add %A[intRes], r1")
A("adc %B[intRes], %[tmp]")
A("lsr r0")
A("adc %A[intRes], %[tmp]")
A("adc %B[intRes], %[tmp]")
A("clr r1")
: [intRes] "=&r" (intRes),
[tmp] "=&r" (tmp)
: [charIn1] "d" (charIn1),
[intIn2] "d" (intIn2)
: "cc"
);
return intRes;
}

400
src/HAL/AVR/pinsDebug.h Normal file
View File

@ -0,0 +1,400 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* PWM print routines for Atmel 8 bit AVR CPUs
*/
#include "../../inc/MarlinConfig.h"
#define NUMBER_PINS_TOTAL NUM_DIGITAL_PINS
#if MB(BQ_ZUM_MEGA_3D, MIGHTYBOARD_REVE, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
#define AVR_ATmega2560_FAMILY_PLUS_70 1
#endif
#if AVR_AT90USB1286_FAMILY
// Working with Teensyduino extension so need to re-define some things
#include "pinsDebug_Teensyduino.h"
// Can't use the "digitalPinToPort" function from the Teensyduino type IDEs
// portModeRegister takes a different argument
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort(p)
#define GET_PINMODE(pin) (*portModeRegister(pin) & digitalPinToBitMask_DEBUG(pin))
#elif AVR_ATmega2560_FAMILY_PLUS_70 // So we can access/display all the pins on boards using more than 70
#include "pinsDebug_plus_70.h"
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer_plus_70(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask_plus_70(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort_plus_70(p)
bool GET_PINMODE(int8_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); }
#else
#define digitalPinToTimer_DEBUG(p) digitalPinToTimer(p)
#define digitalPinToBitMask_DEBUG(p) digitalPinToBitMask(p)
#define digitalPinToPort_DEBUG(p) digitalPinToPort(p)
bool GET_PINMODE(int8_t pin) {return *portModeRegister(digitalPinToPort_DEBUG(pin)) & digitalPinToBitMask_DEBUG(pin); }
#define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin)
#endif
#define VALID_PIN(pin) (pin >= 0 && pin < NUM_DIGITAL_PINS ? 1 : 0)
#if AVR_ATmega1284_FAMILY
#define DIGITAL_PIN_TO_ANALOG_PIN(P) int(analogInputToDigitalPin(0) - (P))
#define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(7) && (P) <= analogInputToDigitalPin(0))
#else
#define DIGITAL_PIN_TO_ANALOG_PIN(P) int((P) - analogInputToDigitalPin(0))
#define IS_ANALOG(P) ((P) >= analogInputToDigitalPin(0) && ((P) <= analogInputToDigitalPin(15) || (P) <= analogInputToDigitalPin(7)))
#endif
#define GET_ARRAY_PIN(p) pgm_read_byte(&pin_array[p].pin)
#define MULTI_NAME_PAD 26 // space needed to be pretty if not first name assigned to a pin
void PRINT_ARRAY_NAME(uint8_t x) {
PGM_P const name_mem_pointer = (PGM_P)pgm_read_ptr(&pin_array[x].name);
LOOP_L_N(y, MAX_NAME_LENGTH) {
char temp_char = pgm_read_byte(name_mem_pointer + y);
if (temp_char != 0)
SERIAL_CHAR(temp_char);
else {
LOOP_L_N(i, MAX_NAME_LENGTH - y) SERIAL_CHAR(' ');
break;
}
}
}
#define GET_ARRAY_IS_DIGITAL(x) pgm_read_byte(&pin_array[x].is_digital)
#if defined(__AVR_ATmega1284P__) // 1284 IDE extensions set this to the number of
#undef NUM_DIGITAL_PINS // digital only pins while all other CPUs have it
#define NUM_DIGITAL_PINS 32 // set to digital only + digital/analog
#endif
#define PWM_PRINT(V) do{ sprintf_P(buffer, PSTR("PWM: %4d"), V); SERIAL_ECHO(buffer); }while(0)
#define PWM_CASE(N,Z) \
case TIMER##N##Z: \
if (TCCR##N##A & (_BV(COM##N##Z##1) | _BV(COM##N##Z##0))) { \
PWM_PRINT(OCR##N##Z); \
return true; \
} else return false
#define ABTEST(N) defined(TCCR##N##A) && defined(COM##N##A1)
/**
* Print a pin's PWM status.
* Return true if it's currently a PWM pin.
*/
static bool pwm_status(uint8_t pin) {
char buffer[20]; // for the sprintf statements
switch (digitalPinToTimer_DEBUG(pin)) {
#if ABTEST(0)
#ifdef TIMER0A
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
PWM_CASE(0, A);
#endif
#endif
PWM_CASE(0, B);
#endif
#if ABTEST(1)
PWM_CASE(1, A);
PWM_CASE(1, B);
#if defined(COM1C1) && defined(TIMER1C)
PWM_CASE(1, C);
#endif
#endif
#if ABTEST(2)
PWM_CASE(2, A);
PWM_CASE(2, B);
#endif
#if ABTEST(3)
PWM_CASE(3, A);
PWM_CASE(3, B);
#ifdef COM3C1
PWM_CASE(3, C);
#endif
#endif
#ifdef TCCR4A
PWM_CASE(4, A);
PWM_CASE(4, B);
PWM_CASE(4, C);
#endif
#if ABTEST(5)
PWM_CASE(5, A);
PWM_CASE(5, B);
PWM_CASE(5, C);
#endif
case NOT_ON_TIMER:
default:
return false;
}
SERIAL_ECHO_SP(2);
} // pwm_status
const volatile uint8_t* const PWM_other[][3] PROGMEM = {
{ &TCCR0A, &TCCR0B, &TIMSK0 },
{ &TCCR1A, &TCCR1B, &TIMSK1 },
#if ABTEST(2)
{ &TCCR2A, &TCCR2B, &TIMSK2 },
#endif
#if ABTEST(3)
{ &TCCR3A, &TCCR3B, &TIMSK3 },
#endif
#ifdef TCCR4A
{ &TCCR4A, &TCCR4B, &TIMSK4 },
#endif
#if ABTEST(5)
{ &TCCR5A, &TCCR5B, &TIMSK5 },
#endif
};
const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
#ifdef TIMER0A
{ &OCR0A, &OCR0B, 0 },
#else
{ 0, &OCR0B, 0 },
#endif
#if defined(COM1C1) && defined(TIMER1C)
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, (const uint8_t*)&OCR1C },
#else
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, 0 },
#endif
#if ABTEST(2)
{ &OCR2A, &OCR2B, 0 },
#endif
#if ABTEST(3)
#ifdef COM3C1
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, (const uint8_t*)&OCR3C },
#else
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, 0 },
#endif
#endif
#ifdef TCCR4A
{ (const uint8_t*)&OCR4A, (const uint8_t*)&OCR4B, (const uint8_t*)&OCR4C },
#endif
#if ABTEST(5)
{ (const uint8_t*)&OCR5A, (const uint8_t*)&OCR5B, (const uint8_t*)&OCR5C },
#endif
};
#define TCCR_A(T) pgm_read_word(&PWM_other[T][0])
#define TCCR_B(T) pgm_read_word(&PWM_other[T][1])
#define TIMSK(T) pgm_read_word(&PWM_other[T][2])
#define CS_0 0
#define CS_1 1
#define CS_2 2
#define WGM_0 0
#define WGM_1 1
#define WGM_2 3
#define WGM_3 4
#define TOIE 0
#define OCR_VAL(T, L) pgm_read_word(&PWM_OCR[T][L])
static void err_is_counter() { SERIAL_ECHOPGM(" non-standard PWM mode"); }
static void err_is_interrupt() { SERIAL_ECHOPGM(" compare interrupt enabled"); }
static void err_prob_interrupt() { SERIAL_ECHOPGM(" overflow interrupt enabled"); }
static void print_is_also_tied() { SERIAL_ECHOPGM(" is also tied to this pin"); SERIAL_ECHO_SP(14); }
inline void com_print(const uint8_t N, const uint8_t Z) {
const uint8_t *TCCRA = (uint8_t*)TCCR_A(N);
SERIAL_ECHOPGM(" COM", AS_DIGIT(N));
SERIAL_CHAR(Z);
SERIAL_ECHOPGM(": ", int((*TCCRA >> (6 - Z * 2)) & 0x03));
}
void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N - WGM bit layout
char buffer[20]; // for the sprintf statements
const uint8_t *TCCRB = (uint8_t*)TCCR_B(T),
*TCCRA = (uint8_t*)TCCR_A(T);
uint8_t WGM = (((*TCCRB & _BV(WGM_2)) >> 1) | (*TCCRA & (_BV(WGM_0) | _BV(WGM_1))));
if (N == 4) WGM |= ((*TCCRB & _BV(WGM_3)) >> 1);
SERIAL_ECHOPGM(" TIMER", AS_DIGIT(T));
SERIAL_CHAR(L);
SERIAL_ECHO_SP(3);
if (N == 3) {
const uint8_t *OCRVAL8 = (uint8_t*)OCR_VAL(T, L - 'A');
PWM_PRINT(*OCRVAL8);
}
else {
const uint16_t *OCRVAL16 = (uint16_t*)OCR_VAL(T, L - 'A');
PWM_PRINT(*OCRVAL16);
}
SERIAL_ECHOPGM(" WGM: ", WGM);
com_print(T,L);
SERIAL_ECHOPGM(" CS: ", (*TCCRB & (_BV(CS_0) | _BV(CS_1) | _BV(CS_2)) ));
SERIAL_ECHOPGM(" TCCR", AS_DIGIT(T), "A: ", *TCCRA);
SERIAL_ECHOPGM(" TCCR", AS_DIGIT(T), "B: ", *TCCRB);
const uint8_t *TMSK = (uint8_t*)TIMSK(T);
SERIAL_ECHOPGM(" TIMSK", AS_DIGIT(T), ": ", *TMSK);
const uint8_t OCIE = L - 'A' + 1;
if (N == 3) { if (WGM == 0 || WGM == 2 || WGM == 4 || WGM == 6) err_is_counter(); }
else { if (WGM == 0 || WGM == 4 || WGM == 12 || WGM == 13) err_is_counter(); }
if (TEST(*TMSK, OCIE)) err_is_interrupt();
if (TEST(*TMSK, TOIE)) err_prob_interrupt();
}
static void pwm_details(uint8_t pin) {
switch (digitalPinToTimer_DEBUG(pin)) {
#if ABTEST(0)
#ifdef TIMER0A
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
case TIMER0A: timer_prefix(0, 'A', 3); break;
#endif
#endif
case TIMER0B: timer_prefix(0, 'B', 3); break;
#endif
#if ABTEST(1)
case TIMER1A: timer_prefix(1, 'A', 4); break;
case TIMER1B: timer_prefix(1, 'B', 4); break;
#if defined(COM1C1) && defined(TIMER1C)
case TIMER1C: timer_prefix(1, 'C', 4); break;
#endif
#endif
#if ABTEST(2)
case TIMER2A: timer_prefix(2, 'A', 3); break;
case TIMER2B: timer_prefix(2, 'B', 3); break;
#endif
#if ABTEST(3)
case TIMER3A: timer_prefix(3, 'A', 4); break;
case TIMER3B: timer_prefix(3, 'B', 4); break;
#ifdef COM3C1
case TIMER3C: timer_prefix(3, 'C', 4); break;
#endif
#endif
#ifdef TCCR4A
case TIMER4A: timer_prefix(4, 'A', 4); break;
case TIMER4B: timer_prefix(4, 'B', 4); break;
case TIMER4C: timer_prefix(4, 'C', 4); break;
#endif
#if ABTEST(5)
case TIMER5A: timer_prefix(5, 'A', 4); break;
case TIMER5B: timer_prefix(5, 'B', 4); break;
case TIMER5C: timer_prefix(5, 'C', 4); break;
#endif
case NOT_ON_TIMER: break;
}
SERIAL_ECHOPGM(" ");
// on pins that have two PWMs, print info on second PWM
#if AVR_ATmega2560_FAMILY || AVR_AT90USB1286_FAMILY
// looking for port B7 - PWMs 0A and 1C
if (digitalPinToPort_DEBUG(pin) == 'B' - 64 && 0x80 == digitalPinToBitMask_DEBUG(pin)) {
#if !AVR_AT90USB1286_FAMILY
SERIAL_ECHOPGM("\n .");
SERIAL_ECHO_SP(18);
SERIAL_ECHOPGM("TIMER1C");
print_is_also_tied();
timer_prefix(1, 'C', 4);
#else
SERIAL_ECHOPGM("\n .");
SERIAL_ECHO_SP(18);
SERIAL_ECHOPGM("TIMER0A");
print_is_also_tied();
timer_prefix(0, 'A', 3);
#endif
}
#else
UNUSED(print_is_also_tied);
#endif
} // pwm_details
#ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs
int digitalRead_mod(const int8_t pin) { // same as digitalRead except the PWM stop section has been removed
const uint8_t port = digitalPinToPort_DEBUG(pin);
return (port != NOT_A_PIN) && (*portInputRegister(port) & digitalPinToBitMask_DEBUG(pin)) ? HIGH : LOW;
}
#endif
#ifndef PRINT_PORT
void print_port(int8_t pin) { // print port number
#ifdef digitalPinToPort_DEBUG
uint8_t x;
SERIAL_ECHOPGM(" Port: ");
#if AVR_AT90USB1286_FAMILY
x = (pin == 46 || pin == 47) ? 'E' : digitalPinToPort_DEBUG(pin) + 64;
#else
x = digitalPinToPort_DEBUG(pin) + 64;
#endif
SERIAL_CHAR(x);
#if AVR_AT90USB1286_FAMILY
if (pin == 46)
x = '2';
else if (pin == 47)
x = '3';
else {
uint8_t temp = digitalPinToBitMask_DEBUG(pin);
for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1;
}
#else
uint8_t temp = digitalPinToBitMask_DEBUG(pin);
for (x = '0'; x < '9' && temp != 1; x++) temp >>= 1;
#endif
SERIAL_CHAR(x);
#else
SERIAL_ECHO_SP(10);
#endif
}
#define PRINT_PORT(p) print_port(p)
#endif
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0)
#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0)
#undef ABTEST

View File

@ -0,0 +1,111 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
//
// some of the pin mapping functions of the Teensduino extension to the Arduino IDE
// do not function the same as the other Arduino extensions
//
#define TEENSYDUINO_IDE
//digitalPinToTimer(pin) function works like Arduino but Timers are not defined
#define TIMER0B 1
#define TIMER1A 7
#define TIMER1B 8
#define TIMER1C 9
#define TIMER2A 6
#define TIMER2B 2
#define TIMER3A 5
#define TIMER3B 4
#define TIMER3C 3
// digitalPinToPort function just returns the pin number so need to create our own
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#undef digitalPinToPort
const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
PD, // 0 - PD0 - INT0 - PWM
PD, // 1 - PD1 - INT1 - PWM
PD, // 2 - PD2 - INT2 - RX
PD, // 3 - PD3 - INT3 - TX
PD, // 4 - PD4
PD, // 5 - PD5
PD, // 6 - PD6
PD, // 7 - PD7
PE, // 8 - PE0
PE, // 9 - PE1
PC, // 10 - PC0
PC, // 11 - PC1
PC, // 12 - PC2
PC, // 13 - PC3
PC, // 14 - PC4 - PWM
PC, // 15 - PC5 - PWM
PC, // 16 - PC6 - PWM
PC, // 17 - PC7
PE, // 18 - PE6 - INT6
PE, // 19 - PE7 - INT7
PB, // 20 - PB0
PB, // 21 - PB1
PB, // 22 - PB2
PB, // 23 - PB3
PB, // 24 - PB4 - PWM
PB, // 25 - PB5 - PWM
PB, // 26 - PB6 - PWM
PB, // 27 - PB7 - PWM
PA, // 28 - PA0
PA, // 29 - PA1
PA, // 30 - PA2
PA, // 31 - PA3
PA, // 32 - PA4
PA, // 33 - PA5
PA, // 34 - PA6
PA, // 35 - PA7
PE, // 36 - PE4 - INT4
PE, // 37 - PE5 - INT5
PF, // 38 - PF0 - A0
PF, // 39 - PF1 - A1
PF, // 40 - PF2 - A2
PF, // 41 - PF3 - A3
PF, // 42 - PF4 - A4
PF, // 43 - PF5 - A5
PF, // 44 - PF6 - A6
PF, // 45 - PF7 - A7
PE, // 46 - PE2 (not defined in teensyduino)
PE, // 47 - PE3 (not defined in teensyduino)
};
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
// digitalPinToBitMask(pin) is OK
#define digitalRead_mod(p) extDigitalRead(p) // Teensyduino's version of digitalRead doesn't
// disable the PWMs so we can use it as is
// portModeRegister(pin) is OK

View File

@ -0,0 +1,332 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Structures for 2560 family boards that use more than 70 pins
*/
#if MB(BQ_ZUM_MEGA_3D, MINIRAMBO, SCOOVO_X9H, TRIGORILLA_14)
#undef NUM_DIGITAL_PINS
#define NUM_DIGITAL_PINS 85
#elif MB(MIGHTYBOARD_REVE)
#undef NUM_DIGITAL_PINS
#define NUM_DIGITAL_PINS 80
#endif
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#define PG 7
#define PH 8
#define PJ 10
#define PK 11
#define PL 12
const uint8_t PROGMEM digital_pin_to_port_PGM_plus_70[] = {
// PORTLIST
// ------------------------
PE , // PE 0 ** 0 ** USART0_RX
PE , // PE 1 ** 1 ** USART0_TX
PE , // PE 4 ** 2 ** PWM2
PE , // PE 5 ** 3 ** PWM3
PG , // PG 5 ** 4 ** PWM4
PE , // PE 3 ** 5 ** PWM5
PH , // PH 3 ** 6 ** PWM6
PH , // PH 4 ** 7 ** PWM7
PH , // PH 5 ** 8 ** PWM8
PH , // PH 6 ** 9 ** PWM9
PB , // PB 4 ** 10 ** PWM10
PB , // PB 5 ** 11 ** PWM11
PB , // PB 6 ** 12 ** PWM12
PB , // PB 7 ** 13 ** PWM13
PJ , // PJ 1 ** 14 ** USART3_TX
PJ , // PJ 0 ** 15 ** USART3_RX
PH , // PH 1 ** 16 ** USART2_TX
PH , // PH 0 ** 17 ** USART2_RX
PD , // PD 3 ** 18 ** USART1_TX
PD , // PD 2 ** 19 ** USART1_RX
PD , // PD 1 ** 20 ** I2C_SDA
PD , // PD 0 ** 21 ** I2C_SCL
PA , // PA 0 ** 22 ** D22
PA , // PA 1 ** 23 ** D23
PA , // PA 2 ** 24 ** D24
PA , // PA 3 ** 25 ** D25
PA , // PA 4 ** 26 ** D26
PA , // PA 5 ** 27 ** D27
PA , // PA 6 ** 28 ** D28
PA , // PA 7 ** 29 ** D29
PC , // PC 7 ** 30 ** D30
PC , // PC 6 ** 31 ** D31
PC , // PC 5 ** 32 ** D32
PC , // PC 4 ** 33 ** D33
PC , // PC 3 ** 34 ** D34
PC , // PC 2 ** 35 ** D35
PC , // PC 1 ** 36 ** D36
PC , // PC 0 ** 37 ** D37
PD , // PD 7 ** 38 ** D38
PG , // PG 2 ** 39 ** D39
PG , // PG 1 ** 40 ** D40
PG , // PG 0 ** 41 ** D41
PL , // PL 7 ** 42 ** D42
PL , // PL 6 ** 43 ** D43
PL , // PL 5 ** 44 ** D44
PL , // PL 4 ** 45 ** D45
PL , // PL 3 ** 46 ** D46
PL , // PL 2 ** 47 ** D47
PL , // PL 1 ** 48 ** D48
PL , // PL 0 ** 49 ** D49
PB , // PB 3 ** 50 ** SPI_MISO
PB , // PB 2 ** 51 ** SPI_MOSI
PB , // PB 1 ** 52 ** SPI_SCK
PB , // PB 0 ** 53 ** SPI_SS
PF , // PF 0 ** 54 ** A0
PF , // PF 1 ** 55 ** A1
PF , // PF 2 ** 56 ** A2
PF , // PF 3 ** 57 ** A3
PF , // PF 4 ** 58 ** A4
PF , // PF 5 ** 59 ** A5
PF , // PF 6 ** 60 ** A6
PF , // PF 7 ** 61 ** A7
PK , // PK 0 ** 62 ** A8
PK , // PK 1 ** 63 ** A9
PK , // PK 2 ** 64 ** A10
PK , // PK 3 ** 65 ** A11
PK , // PK 4 ** 66 ** A12
PK , // PK 5 ** 67 ** A13
PK , // PK 6 ** 68 ** A14
PK , // PK 7 ** 69 ** A15
PG , // PG 4 ** 70 **
PG , // PG 3 ** 71 **
PJ , // PJ 2 ** 72 **
PJ , // PJ 3 ** 73 **
PJ , // PJ 7 ** 74 **
PJ , // PJ 4 ** 75 **
PJ , // PJ 5 ** 76 **
PJ , // PJ 6 ** 77 **
PE , // PE 2 ** 78 **
PE , // PE 6 ** 79 **
PE , // PE 7 ** 80 **
PD , // PD 4 ** 81 **
PD , // PD 5 ** 82 **
PD , // PD 6 ** 83 **
PH , // PH 2 ** 84 **
PH , // PH 7 ** 85 **
};
#define digitalPinToPort_plus_70(P) ( pgm_read_byte( digital_pin_to_port_PGM_plus_70 + (P) ) )
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM_plus_70[] = {
// PIN IN PORT
// ------------------------
_BV( 0 ) , // PE 0 ** 0 ** USART0_RX
_BV( 1 ) , // PE 1 ** 1 ** USART0_TX
_BV( 4 ) , // PE 4 ** 2 ** PWM2
_BV( 5 ) , // PE 5 ** 3 ** PWM3
_BV( 5 ) , // PG 5 ** 4 ** PWM4
_BV( 3 ) , // PE 3 ** 5 ** PWM5
_BV( 3 ) , // PH 3 ** 6 ** PWM6
_BV( 4 ) , // PH 4 ** 7 ** PWM7
_BV( 5 ) , // PH 5 ** 8 ** PWM8
_BV( 6 ) , // PH 6 ** 9 ** PWM9
_BV( 4 ) , // PB 4 ** 10 ** PWM10
_BV( 5 ) , // PB 5 ** 11 ** PWM11
_BV( 6 ) , // PB 6 ** 12 ** PWM12
_BV( 7 ) , // PB 7 ** 13 ** PWM13
_BV( 1 ) , // PJ 1 ** 14 ** USART3_TX
_BV( 0 ) , // PJ 0 ** 15 ** USART3_RX
_BV( 1 ) , // PH 1 ** 16 ** USART2_TX
_BV( 0 ) , // PH 0 ** 17 ** USART2_RX
_BV( 3 ) , // PD 3 ** 18 ** USART1_TX
_BV( 2 ) , // PD 2 ** 19 ** USART1_RX
_BV( 1 ) , // PD 1 ** 20 ** I2C_SDA
_BV( 0 ) , // PD 0 ** 21 ** I2C_SCL
_BV( 0 ) , // PA 0 ** 22 ** D22
_BV( 1 ) , // PA 1 ** 23 ** D23
_BV( 2 ) , // PA 2 ** 24 ** D24
_BV( 3 ) , // PA 3 ** 25 ** D25
_BV( 4 ) , // PA 4 ** 26 ** D26
_BV( 5 ) , // PA 5 ** 27 ** D27
_BV( 6 ) , // PA 6 ** 28 ** D28
_BV( 7 ) , // PA 7 ** 29 ** D29
_BV( 7 ) , // PC 7 ** 30 ** D30
_BV( 6 ) , // PC 6 ** 31 ** D31
_BV( 5 ) , // PC 5 ** 32 ** D32
_BV( 4 ) , // PC 4 ** 33 ** D33
_BV( 3 ) , // PC 3 ** 34 ** D34
_BV( 2 ) , // PC 2 ** 35 ** D35
_BV( 1 ) , // PC 1 ** 36 ** D36
_BV( 0 ) , // PC 0 ** 37 ** D37
_BV( 7 ) , // PD 7 ** 38 ** D38
_BV( 2 ) , // PG 2 ** 39 ** D39
_BV( 1 ) , // PG 1 ** 40 ** D40
_BV( 0 ) , // PG 0 ** 41 ** D41
_BV( 7 ) , // PL 7 ** 42 ** D42
_BV( 6 ) , // PL 6 ** 43 ** D43
_BV( 5 ) , // PL 5 ** 44 ** D44
_BV( 4 ) , // PL 4 ** 45 ** D45
_BV( 3 ) , // PL 3 ** 46 ** D46
_BV( 2 ) , // PL 2 ** 47 ** D47
_BV( 1 ) , // PL 1 ** 48 ** D48
_BV( 0 ) , // PL 0 ** 49 ** D49
_BV( 3 ) , // PB 3 ** 50 ** SPI_MISO
_BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI
_BV( 1 ) , // PB 1 ** 52 ** SPI_SCK
_BV( 0 ) , // PB 0 ** 53 ** SPI_SS
_BV( 0 ) , // PF 0 ** 54 ** A0
_BV( 1 ) , // PF 1 ** 55 ** A1
_BV( 2 ) , // PF 2 ** 56 ** A2
_BV( 3 ) , // PF 3 ** 57 ** A3
_BV( 4 ) , // PF 4 ** 58 ** A4
_BV( 5 ) , // PF 5 ** 59 ** A5
_BV( 6 ) , // PF 6 ** 60 ** A6
_BV( 7 ) , // PF 7 ** 61 ** A7
_BV( 0 ) , // PK 0 ** 62 ** A8
_BV( 1 ) , // PK 1 ** 63 ** A9
_BV( 2 ) , // PK 2 ** 64 ** A10
_BV( 3 ) , // PK 3 ** 65 ** A11
_BV( 4 ) , // PK 4 ** 66 ** A12
_BV( 5 ) , // PK 5 ** 67 ** A13
_BV( 6 ) , // PK 6 ** 68 ** A14
_BV( 7 ) , // PK 7 ** 69 ** A15
_BV( 4 ) , // PG 4 ** 70 **
_BV( 3 ) , // PG 3 ** 71 **
_BV( 2 ) , // PJ 2 ** 72 **
_BV( 3 ) , // PJ 3 ** 73 **
_BV( 7 ) , // PJ 7 ** 74 **
_BV( 4 ) , // PJ 4 ** 75 **
_BV( 5 ) , // PJ 5 ** 76 **
_BV( 6 ) , // PJ 6 ** 77 **
_BV( 2 ) , // PE 2 ** 78 **
_BV( 6 ) , // PE 6 ** 79 **
_BV( 7 ) , // PE 7 ** 80 **
_BV( 4 ) , // PD 4 ** 81 **
_BV( 5 ) , // PD 5 ** 82 **
_BV( 6 ) , // PD 6 ** 83 **
_BV( 2 ) , // PH 2 ** 84 **
_BV( 7 ) , // PH 7 ** 85 **
};
#define digitalPinToBitMask_plus_70(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM_plus_70 + (P) ) )
const uint8_t PROGMEM digital_pin_to_timer_PGM_plus_70[] = {
// TIMERS
// ------------------------
NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX
NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX
TIMER3B , // PE 4 ** 2 ** PWM2
TIMER3C , // PE 5 ** 3 ** PWM3
TIMER0B , // PG 5 ** 4 ** PWM4
TIMER3A , // PE 3 ** 5 ** PWM5
TIMER4A , // PH 3 ** 6 ** PWM6
TIMER4B , // PH 4 ** 7 ** PWM7
TIMER4C , // PH 5 ** 8 ** PWM8
TIMER2B , // PH 6 ** 9 ** PWM9
TIMER2A , // PB 4 ** 10 ** PWM10
TIMER1A , // PB 5 ** 11 ** PWM11
TIMER1B , // PB 6 ** 12 ** PWM12
TIMER0A , // PB 7 ** 13 ** PWM13
NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX
NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX
NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX
NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX
NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX
NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX
NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA
NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL
NOT_ON_TIMER , // PA 0 ** 22 ** D22
NOT_ON_TIMER , // PA 1 ** 23 ** D23
NOT_ON_TIMER , // PA 2 ** 24 ** D24
NOT_ON_TIMER , // PA 3 ** 25 ** D25
NOT_ON_TIMER , // PA 4 ** 26 ** D26
NOT_ON_TIMER , // PA 5 ** 27 ** D27
NOT_ON_TIMER , // PA 6 ** 28 ** D28
NOT_ON_TIMER , // PA 7 ** 29 ** D29
NOT_ON_TIMER , // PC 7 ** 30 ** D30
NOT_ON_TIMER , // PC 6 ** 31 ** D31
NOT_ON_TIMER , // PC 5 ** 32 ** D32
NOT_ON_TIMER , // PC 4 ** 33 ** D33
NOT_ON_TIMER , // PC 3 ** 34 ** D34
NOT_ON_TIMER , // PC 2 ** 35 ** D35
NOT_ON_TIMER , // PC 1 ** 36 ** D36
NOT_ON_TIMER , // PC 0 ** 37 ** D37
NOT_ON_TIMER , // PD 7 ** 38 ** D38
NOT_ON_TIMER , // PG 2 ** 39 ** D39
NOT_ON_TIMER , // PG 1 ** 40 ** D40
NOT_ON_TIMER , // PG 0 ** 41 ** D41
NOT_ON_TIMER , // PL 7 ** 42 ** D42
NOT_ON_TIMER , // PL 6 ** 43 ** D43
TIMER5C , // PL 5 ** 44 ** D44
TIMER5B , // PL 4 ** 45 ** D45
TIMER5A , // PL 3 ** 46 ** D46
NOT_ON_TIMER , // PL 2 ** 47 ** D47
NOT_ON_TIMER , // PL 1 ** 48 ** D48
NOT_ON_TIMER , // PL 0 ** 49 ** D49
NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO
NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI
NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK
NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS
NOT_ON_TIMER , // PF 0 ** 54 ** A0
NOT_ON_TIMER , // PF 1 ** 55 ** A1
NOT_ON_TIMER , // PF 2 ** 56 ** A2
NOT_ON_TIMER , // PF 3 ** 57 ** A3
NOT_ON_TIMER , // PF 4 ** 58 ** A4
NOT_ON_TIMER , // PF 5 ** 59 ** A5
NOT_ON_TIMER , // PF 6 ** 60 ** A6
NOT_ON_TIMER , // PF 7 ** 61 ** A7
NOT_ON_TIMER , // PK 0 ** 62 ** A8
NOT_ON_TIMER , // PK 1 ** 63 ** A9
NOT_ON_TIMER , // PK 2 ** 64 ** A10
NOT_ON_TIMER , // PK 3 ** 65 ** A11
NOT_ON_TIMER , // PK 4 ** 66 ** A12
NOT_ON_TIMER , // PK 5 ** 67 ** A13
NOT_ON_TIMER , // PK 6 ** 68 ** A14
NOT_ON_TIMER , // PK 7 ** 69 ** A15
NOT_ON_TIMER , // PG 4 ** 70 **
NOT_ON_TIMER , // PG 3 ** 71 **
NOT_ON_TIMER , // PJ 2 ** 72 **
NOT_ON_TIMER , // PJ 3 ** 73 **
NOT_ON_TIMER , // PJ 7 ** 74 **
NOT_ON_TIMER , // PJ 4 ** 75 **
NOT_ON_TIMER , // PJ 5 ** 76 **
NOT_ON_TIMER , // PJ 6 ** 77 **
NOT_ON_TIMER , // PE 2 ** 78 **
NOT_ON_TIMER , // PE 6 ** 79 **
};
#define digitalPinToTimer_plus_70(P) ( pgm_read_byte( digital_pin_to_timer_PGM_plus_70 + (P) ) )
/**
* Interrupts that are not implemented
*
* INT6 E6 79
* INT7 E7 80
* PCINT11 J2 72
* PCINT12 J3 73
* PCINT13 J4 75
* PCINT14 J5 76
* PCINT15 J6 77
*/

65
src/HAL/AVR/spi_pins.h Normal file
View File

@ -0,0 +1,65 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Define SPI Pins: SCK, MISO, MOSI, SS
*/
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
#define AVR_SCK_PIN 13
#define AVR_MISO_PIN 12
#define AVR_MOSI_PIN 11
#define AVR_SS_PIN 10
#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega1284P__)
#define AVR_SCK_PIN 7
#define AVR_MISO_PIN 6
#define AVR_MOSI_PIN 5
#define AVR_SS_PIN 4
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVR_SCK_PIN 52
#define AVR_MISO_PIN 50
#define AVR_MOSI_PIN 51
#define AVR_SS_PIN 53
#elif defined(__AVR_AT90USB1287__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)
#define AVR_SCK_PIN 21
#define AVR_MISO_PIN 23
#define AVR_MOSI_PIN 22
#define AVR_SS_PIN 20
#elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__)
#define AVR_SCK_PIN 10
#define AVR_MISO_PIN 12
#define AVR_MOSI_PIN 11
#define AVR_SS_PIN 16
#endif
#ifndef SD_SCK_PIN
#define SD_SCK_PIN AVR_SCK_PIN
#endif
#ifndef SD_MISO_PIN
#define SD_MISO_PIN AVR_MISO_PIN
#endif
#ifndef SD_MOSI_PIN
#define SD_MOSI_PIN AVR_MOSI_PIN
#endif
#ifndef SD_SS_PIN
#define SD_SS_PIN AVR_SS_PIN
#endif

260
src/HAL/AVR/timers.h Normal file
View File

@ -0,0 +1,260 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdint.h>
// ------------------------
// Types
// ------------------------
typedef uint16_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFF
// ------------------------
// Defines
// ------------------------
#define HAL_TIMER_RATE ((F_CPU) / 8) // i.e., 2MHz or 2.5MHz
#ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 1
#endif
#ifndef MF_TIMER_PULSE
#define MF_TIMER_PULSE MF_TIMER_STEP
#endif
#ifndef MF_TIMER_TEMP
#define MF_TIMER_TEMP 0
#endif
#define TEMP_TIMER_FREQUENCY ((F_CPU) / 64.0 / 256.0)
#define STEPPER_TIMER_RATE HAL_TIMER_RATE
#define STEPPER_TIMER_PRESCALE 8
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // Cannot be of type double
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() SBI(TIMSK1, OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() CBI(TIMSK1, OCIE1A)
#define STEPPER_ISR_ENABLED() TEST(TIMSK1, OCIE1A)
#define ENABLE_TEMPERATURE_INTERRUPT() SBI(TIMSK0, OCIE0A)
#define DISABLE_TEMPERATURE_INTERRUPT() CBI(TIMSK0, OCIE0A)
#define TEMPERATURE_ISR_ENABLED() TEST(TIMSK0, OCIE0A)
FORCE_INLINE void HAL_timer_start(const uint8_t timer_num, const uint32_t) {
switch (timer_num) {
case MF_TIMER_STEP:
// waveform generation = 0100 = CTC
SET_WGM(1, CTC_OCRnA);
// output mode = 00 (disconnected)
SET_COMA(1, NORMAL);
// Set the timer pre-scaler
// Generally we use a divider of 8, resulting in a 2MHz timer
// frequency on a 16MHz MCU. If you are going to change this, be
// sure to regenerate speed_lookuptable.h with
// create_speed_lookuptable.py
SET_CS(1, PRESCALER_8); // CS 2 = 1/8 prescaler
// Init Stepper ISR to 122 Hz for quick starting
// (F_CPU) / (STEPPER_TIMER_PRESCALE) / frequency
OCR1A = 0x4000;
TCNT1 = 0;
break;
case MF_TIMER_TEMP:
// Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt
OCR0A = 128;
break;
}
}
#define TIMER_OCR_1 OCR1A
#define TIMER_COUNTER_1 TCNT1
#define TIMER_OCR_0 OCR0A
#define TIMER_COUNTER_0 TCNT0
#define _CAT(a,V...) a##V
#define HAL_timer_set_compare(timer, compare) (_CAT(TIMER_OCR_, timer) = compare)
#define HAL_timer_get_compare(timer) _CAT(TIMER_OCR_, timer)
#define HAL_timer_get_count(timer) _CAT(TIMER_COUNTER_, timer)
/**
* On AVR there is no hardware prioritization and preemption of
* interrupts, so this emulates it. The UART has first priority
* (otherwise, characters will be lost due to UART overflow).
* Then: Stepper, Endstops, Temperature, and -finally- all others.
*/
#define HAL_timer_isr_prologue(T) NOOP
#define HAL_timer_isr_epilogue(T) NOOP
#ifndef HAL_STEP_TIMER_ISR
/* 18 cycles maximum latency */
#define HAL_STEP_TIMER_ISR() \
extern "C" void TIMER1_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \
extern "C" void TIMER1_COMPA_vect_bottom() asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
void TIMER1_COMPA_vect() { \
__asm__ __volatile__ ( \
A("push r16") /* 2 Save R16 */ \
A("in r16, __SREG__") /* 1 Get SREG */ \
A("push r16") /* 2 Save SREG into stack */ \
A("lds r16, %[timsk0]") /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
A("push r16") /* 2 Save TIMSK0 into the stack */ \
A("andi r16,~%[msk0]") /* 1 Disable the temperature ISR */ \
A("sts %[timsk0], r16") /* 2 And set the new value */ \
A("lds r16, %[timsk1]") /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
A("andi r16,~%[msk1]") /* 1 Disable the stepper ISR */ \
A("sts %[timsk1], r16") /* 2 And set the new value */ \
A("push r16") /* 2 Save TIMSK1 into stack */ \
A("in r16, 0x3B") /* 1 Get RAMPZ register */ \
A("push r16") /* 2 Save RAMPZ into stack */ \
A("in r16, 0x3C") /* 1 Get EIND register */ \
A("push r0") /* C runtime can modify all the following registers without restoring them */ \
A("push r1") \
A("push r18") \
A("push r19") \
A("push r20") \
A("push r21") \
A("push r22") \
A("push r23") \
A("push r24") \
A("push r25") \
A("push r26") \
A("push r27") \
A("push r30") \
A("push r31") \
A("clr r1") /* C runtime expects this register to be 0 */ \
A("call TIMER1_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A("pop r31") \
A("pop r30") \
A("pop r27") \
A("pop r26") \
A("pop r25") \
A("pop r24") \
A("pop r23") \
A("pop r22") \
A("pop r21") \
A("pop r20") \
A("pop r19") \
A("pop r18") \
A("pop r1") \
A("pop r0") \
A("out 0x3C, r16") /* 1 Restore EIND register */ \
A("pop r16") /* 2 Get the original RAMPZ register value */ \
A("out 0x3B, r16") /* 1 Restore RAMPZ register to its original value */ \
A("pop r16") /* 2 Get the original TIMSK1 value but with stepper ISR disabled */ \
A("ori r16,%[msk1]") /* 1 Reenable the stepper ISR */ \
A("cli") /* 1 Disable global interrupts - Reenabling Stepper ISR can reenter amd temperature can reenter, and we want that, if it happens, after this ISR has ended */ \
A("sts %[timsk1], r16") /* 2 And restore the old value - This reenables the stepper ISR */ \
A("pop r16") /* 2 Get the temperature timer Interrupt mask register [TIMSK0] */ \
A("sts %[timsk0], r16") /* 2 And restore the old value - This reenables the temperature ISR */ \
A("pop r16") /* 2 Get the old SREG value */ \
A("out __SREG__, r16") /* 1 And restore the SREG value */ \
A("pop r16") /* 2 Restore R16 value */ \
A("reti") /* 4 Return from interrupt */ \
: \
: [timsk0] "i" ((uint16_t)&TIMSK0), \
[timsk1] "i" ((uint16_t)&TIMSK1), \
[msk0] "M" ((uint8_t)(1<<OCIE0A)),\
[msk1] "M" ((uint8_t)(1<<OCIE1A)) \
: \
); \
} \
void TIMER1_COMPA_vect_bottom()
#endif // HAL_STEP_TIMER_ISR
#ifndef HAL_TEMP_TIMER_ISR
/* 14 cycles maximum latency */
#define HAL_TEMP_TIMER_ISR() \
extern "C" void TIMER0_COMPA_vect() __attribute__ ((signal, naked, used, externally_visible)); \
extern "C" void TIMER0_COMPA_vect_bottom() asm ("TIMER0_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
void TIMER0_COMPA_vect() { \
__asm__ __volatile__ ( \
A("push r16") /* 2 Save R16 */ \
A("in r16, __SREG__") /* 1 Get SREG */ \
A("push r16") /* 2 Save SREG into stack */ \
A("lds r16, %[timsk0]") /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
A("andi r16,~%[msk0]") /* 1 Disable the temperature ISR */ \
A("sts %[timsk0], r16") /* 2 And set the new value */ \
A("sei") /* 1 Enable global interrupts - It is safe, as the temperature ISR is disabled, so we cannot reenter it */ \
A("push r16") /* 2 Save TIMSK0 into stack */ \
A("in r16, 0x3B") /* 1 Get RAMPZ register */ \
A("push r16") /* 2 Save RAMPZ into stack */ \
A("in r16, 0x3C") /* 1 Get EIND register */ \
A("push r0") /* C runtime can modify all the following registers without restoring them */ \
A("push r1") \
A("push r18") \
A("push r19") \
A("push r20") \
A("push r21") \
A("push r22") \
A("push r23") \
A("push r24") \
A("push r25") \
A("push r26") \
A("push r27") \
A("push r30") \
A("push r31") \
A("clr r1") /* C runtime expects this register to be 0 */ \
A("call TIMER0_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */ \
A("pop r31") \
A("pop r30") \
A("pop r27") \
A("pop r26") \
A("pop r25") \
A("pop r24") \
A("pop r23") \
A("pop r22") \
A("pop r21") \
A("pop r20") \
A("pop r19") \
A("pop r18") \
A("pop r1") \
A("pop r0") \
A("out 0x3C, r16") /* 1 Restore EIND register */ \
A("pop r16") /* 2 Get the original RAMPZ register value */ \
A("out 0x3B, r16") /* 1 Restore RAMPZ register to its original value */ \
A("pop r16") /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
A("ori r16,%[msk0]") /* 1 Enable temperature ISR */ \
A("cli") /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don't want to reenter this handler until the current one is done */ \
A("sts %[timsk0], r16") /* 2 And restore the old value */ \
A("pop r16") /* 2 Get the old SREG */ \
A("out __SREG__, r16") /* 1 And restore the SREG value */ \
A("pop r16") /* 2 Restore R16 */ \
A("reti") /* 4 Return from interrupt */ \
: \
: [timsk0] "i"((uint16_t)&TIMSK0), \
[msk0] "M" ((uint8_t)(1<<OCIE0A)) \
: \
); \
} \
void TIMER0_COMPA_vect_bottom()
#endif // HAL_TEMP_TIMER_ISR

View File

@ -0,0 +1,193 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Based on u8g_com_st7920_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2011, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(ARDUINO) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAM)
#include "../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB
#include "../shared/Marduino.h"
#include "../shared/Delay.h"
#include <U8glib-HAL.h>
static uint8_t u8g_bitData, u8g_bitNotData, u8g_bitClock, u8g_bitNotClock;
static volatile uint8_t *u8g_outData, *u8g_outClock;
static void u8g_com_arduino_init_shift_out(uint8_t dataPin, uint8_t clockPin) {
u8g_outData = portOutputRegister(digitalPinToPort(dataPin));
u8g_outClock = portOutputRegister(digitalPinToPort(clockPin));
u8g_bitData = digitalPinToBitMask(dataPin);
u8g_bitClock = digitalPinToBitMask(clockPin);
u8g_bitNotClock = u8g_bitClock;
u8g_bitNotClock ^= 0xFF;
u8g_bitNotData = u8g_bitData;
u8g_bitNotData ^= 0xFF;
}
void u8g_spiSend_sw_AVR_mode_0(uint8_t val) {
uint8_t bitData = u8g_bitData,
bitNotData = u8g_bitNotData,
bitClock = u8g_bitClock,
bitNotClock = u8g_bitNotClock;
volatile uint8_t *outData = u8g_outData,
*outClock = u8g_outClock;
U8G_ATOMIC_START();
LOOP_L_N(i, 8) {
if (val & 0x80)
*outData |= bitData;
else
*outData &= bitNotData;
*outClock |= bitClock;
val <<= 1;
*outClock &= bitNotClock;
}
U8G_ATOMIC_END();
}
void u8g_spiSend_sw_AVR_mode_3(uint8_t val) {
uint8_t bitData = u8g_bitData,
bitNotData = u8g_bitNotData,
bitClock = u8g_bitClock,
bitNotClock = u8g_bitNotClock;
volatile uint8_t *outData = u8g_outData,
*outClock = u8g_outClock;
U8G_ATOMIC_START();
LOOP_L_N(i, 8) {
*outClock &= bitNotClock;
if (val & 0x80)
*outData |= bitData;
else
*outData &= bitNotData;
*outClock |= bitClock;
val <<= 1;
}
U8G_ATOMIC_END();
}
#if ENABLED(FYSETC_MINI_12864)
#define SPISEND_SW_AVR u8g_spiSend_sw_AVR_mode_3
#else
#define SPISEND_SW_AVR u8g_spiSend_sw_AVR_mode_0
#endif
uint8_t u8g_com_HAL_AVR_sw_sp_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
u8g_com_arduino_init_shift_out(u8g->pin_list[U8G_PI_MOSI], u8g->pin_list[U8G_PI_SCK]);
u8g_com_arduino_assign_pin_output_high(u8g);
u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, 0);
u8g_com_arduino_digital_write(u8g, U8G_PI_MOSI, 0);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val);
break;
case U8G_COM_MSG_CHIP_SELECT:
#if ENABLED(FYSETC_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0
if (arg_val) { // SCK idle state needs to be set to the proper idle state before
// the next chip select goes active
u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, 1); // Set SCK to mode 3 idle state before CS goes active
u8g_com_arduino_digital_write(u8g, U8G_PI_CS, LOW);
}
else {
u8g_com_arduino_digital_write(u8g, U8G_PI_CS, HIGH);
u8g_com_arduino_digital_write(u8g, U8G_PI_SCK, 0); // Set SCK to mode 0 idle state after CS goes inactive
}
#else
u8g_com_arduino_digital_write(u8g, U8G_PI_CS, !arg_val);
#endif
break;
case U8G_COM_MSG_WRITE_BYTE:
SPISEND_SW_AVR(arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_AVR(*ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_AVR(u8g_pgm_read(ptr));
ptr++;
arg_val--;
}
}
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_com_arduino_digital_write(u8g, U8G_PI_A0, arg_val);
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB
#endif // ARDUINO_ARCH_SAM

201
src/HAL/DUE/HAL.cpp Normal file
View File

@ -0,0 +1,201 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* HAL for Arduino Due and compatible (SAM3X8E)
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "../../MarlinCore.h"
#include <Wire.h>
#include "usb/usb_task.h"
// ------------------------
// Public Variables
// ------------------------
uint16_t MarlinHAL::adc_result;
// ------------------------
// Public functions
// ------------------------
#if ENABLED(POSTMORTEM_DEBUGGING)
extern void install_min_serial();
#endif
void MarlinHAL::init() {
#if ENABLED(SDSUPPORT)
OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
#endif
usb_task_init(); // Initialize the USB stack
TERN_(POSTMORTEM_DEBUGGING, install_min_serial()); // Install the min serial handler
}
void MarlinHAL::init_board() {
#ifdef BOARD_INIT
BOARD_INIT();
#endif
}
void MarlinHAL::idletask() { usb_task_idle(); } // Perform USB stack housekeeping
uint8_t MarlinHAL::get_reset_source() {
switch ((RSTC->RSTC_SR >> 8) & 0x07) {
case 0: return RST_POWER_ON;
case 1: return RST_BACKUP;
case 2: return RST_WATCHDOG;
case 3: return RST_SOFTWARE;
case 4: return RST_EXTERNAL;
default: return 0;
}
}
void MarlinHAL::reboot() { rstc_start_software_reset(RSTC); }
// ------------------------
// Watchdog Timer
// ------------------------
#if ENABLED(USE_WATCHDOG)
// Initialize watchdog - On SAM3X, Watchdog was already configured
// and enabled or disabled at startup, so no need to reconfigure it
// here.
void MarlinHAL::watchdog_init() { WDT_Restart(WDT); } // Reset watchdog to start clean
// Reset watchdog. MUST be called at least every 4 seconds after the
// first watchdog_init or AVR will go into emergency procedures.
void MarlinHAL::watchdog_refresh() { watchdogReset(); }
#endif
// Override Arduino runtime to either config or disable the watchdog
//
// We need to configure the watchdog as soon as possible in the boot
// process, because watchdog initialization at hardware reset on SAM3X8E
// is unreliable, and there is risk of unintended resets if we delay
// that initialization to a later time.
void watchdogSetup() {
#if ENABLED(USE_WATCHDOG)
// 4 seconds timeout
uint32_t timeout = TERN(WATCHDOG_DURATION_8S, 8000, 4000);
// Calculate timeout value in WDT counter ticks: This assumes
// the slow clock is running at 32.768 kHz watchdog
// frequency is therefore 32768 / 128 = 256 Hz
timeout = (timeout << 8) / 1000;
if (timeout == 0)
timeout = 1;
else if (timeout > 0xFFF)
timeout = 0xFFF;
// We want to enable the watchdog with the specified timeout
uint32_t value =
WDT_MR_WDV(timeout) | // With the specified timeout
WDT_MR_WDD(timeout) | // and no invalid write window
#if !(SAMV70 || SAMV71 || SAME70 || SAMS70)
WDT_MR_WDRPROC | // WDT fault resets processor only - We want
// to keep PIO controller state
#endif
WDT_MR_WDDBGHLT | // WDT stops in debug state.
WDT_MR_WDIDLEHLT; // WDT stops in idle state.
#if ENABLED(WATCHDOG_RESET_MANUAL)
// We enable the watchdog timer, but only for the interrupt.
// Configure WDT to only trigger an interrupt
value |= WDT_MR_WDFIEN; // Enable WDT fault interrupt.
// Disable WDT interrupt (just in case, to avoid triggering it!)
NVIC_DisableIRQ(WDT_IRQn);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Initialize WDT with the given parameters
WDT_Enable(WDT, value);
// Configure and enable WDT interrupt.
NVIC_ClearPendingIRQ(WDT_IRQn);
NVIC_SetPriority(WDT_IRQn, 0); // Use highest priority, so we detect all kinds of lockups
NVIC_EnableIRQ(WDT_IRQn);
#else
// a WDT fault triggers a reset
value |= WDT_MR_WDRSTEN;
// Initialize WDT with the given parameters
WDT_Enable(WDT, value);
#endif
// Reset the watchdog
WDT_Restart(WDT);
#else
// Make sure to completely disable the Watchdog
WDT_Disable(WDT);
#endif
}
// ------------------------
// Free Memory Accessor
// ------------------------
extern "C" {
extern unsigned int _ebss; // end of bss section
}
// Return free memory between end of heap (or end bss) and whatever is current
int freeMemory() {
int free_memory, heap_end = (int)_sbrk(0);
return (int)&free_memory - (heap_end ?: (int)&_ebss);
}
// ------------------------
// Serial Ports
// ------------------------
// Forward the default serial ports
#if USING_HW_SERIAL0
DefaultSerial1 MSerial0(false, Serial);
#endif
#if USING_HW_SERIAL1
DefaultSerial2 MSerial1(false, Serial1);
#endif
#if USING_HW_SERIAL2
DefaultSerial3 MSerial2(false, Serial2);
#endif
#if USING_HW_SERIAL3
DefaultSerial4 MSerial3(false, Serial3);
#endif
#endif // ARDUINO_ARCH_SAM

233
src/HAL/DUE/HAL.h Normal file
View File

@ -0,0 +1,233 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* HAL for Arduino Due and compatible (SAM3X8E)
*/
#define CPU_32_BIT
#include "../shared/Marduino.h"
#include "../shared/eeprom_if.h"
#include "../shared/math_32bit.h"
#include "../shared/HAL_SPI.h"
#include "fastio.h"
#include <stdint.h>
#include "../../core/serial_hook.h"
// ------------------------
// Serial ports
// ------------------------
typedef ForwardSerial1Class< decltype(Serial) > DefaultSerial1;
typedef ForwardSerial1Class< decltype(Serial1) > DefaultSerial2;
typedef ForwardSerial1Class< decltype(Serial2) > DefaultSerial3;
typedef ForwardSerial1Class< decltype(Serial3) > DefaultSerial4;
extern DefaultSerial1 MSerial0;
extern DefaultSerial2 MSerial1;
extern DefaultSerial3 MSerial2;
extern DefaultSerial4 MSerial3;
#define _MSERIAL(X) MSerial##X
#define MSERIAL(X) _MSERIAL(X)
#if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL1 customizedSerial1
#elif WITHIN(SERIAL_PORT, 0, 3)
#define MYSERIAL1 MSERIAL(SERIAL_PORT)
#else
#error "The required SERIAL_PORT must be from 0 to 3, or -1 for USB Serial."
#endif
#ifdef SERIAL_PORT_2
#if SERIAL_PORT_2 == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL2 customizedSerial2
#elif WITHIN(SERIAL_PORT_2, 0, 3)
#define MYSERIAL2 MSERIAL(SERIAL_PORT_2)
#else
#error "SERIAL_PORT_2 must be from 0 to 3, or -1 for USB Serial."
#endif
#endif
#ifdef SERIAL_PORT_3
#if SERIAL_PORT_3 == -1 || ENABLED(EMERGENCY_PARSER)
#define MYSERIAL3 customizedSerial3
#elif WITHIN(SERIAL_PORT_3, 0, 3)
#define MYSERIAL3 MSERIAL(SERIAL_PORT_3)
#else
#error "SERIAL_PORT_3 must be from 0 to 3, or -1 for USB Serial."
#endif
#endif
#ifdef MMU2_SERIAL_PORT
#if WITHIN(MMU2_SERIAL_PORT, 0, 3)
#define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
#else
#error "MMU2_SERIAL_PORT must be from 0 to 3."
#endif
#endif
#ifdef LCD_SERIAL_PORT
#if WITHIN(LCD_SERIAL_PORT, 0, 3)
#define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
#else
#error "LCD_SERIAL_PORT must be from 0 to 3."
#endif
#endif
#include "MarlinSerial.h"
#include "MarlinSerialUSB.h"
// ------------------------
// Types
// ------------------------
typedef int8_t pin_t;
#define SHARED_SERVOS HAS_SERVOS // Use shared/servos.cpp
class Servo;
typedef Servo hal_servo_t;
//
// Interrupts
//
#define sei() interrupts()
#define cli() noInterrupts()
#define CRITICAL_SECTION_START() const bool _irqon = hal.isr_state(); hal.isr_off()
#define CRITICAL_SECTION_END() if (_irqon) hal.isr_on()
//
// ADC
//
#define HAL_ADC_VREF 3.3
#define HAL_ADC_RESOLUTION 10
#ifndef analogInputToDigitalPin
#define analogInputToDigitalPin(p) ((p < 12U) ? (p) + 54U : -1)
#endif
//
// Pin Mapping for M42, M43, M226
//
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
//
// Tone
//
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0);
void noTone(const pin_t _pin);
// ------------------------
// Class Utilities
// ------------------------
#pragma GCC diagnostic push
#if GCC_VERSION <= 50000
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
#pragma GCC diagnostic pop
#ifdef __cplusplus
extern "C" {
#endif
char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s);
#ifdef __cplusplus
}
#endif
// Return free RAM between end of heap (or end bss) and whatever is current
int freeMemory();
// ------------------------
// MarlinHAL Class
// ------------------------
class MarlinHAL {
public:
// Earliest possible init, before setup()
MarlinHAL() {}
// Watchdog
static void watchdog_init() IF_DISABLED(USE_WATCHDOG, {});
static void watchdog_refresh() IF_DISABLED(USE_WATCHDOG, {});
static void init(); // Called early in setup()
static void init_board(); // Called less early in setup()
static void reboot(); // Restart the firmware
// Interrupts
static bool isr_state() { return !__get_PRIMASK(); }
static void isr_on() { __enable_irq(); }
static void isr_off() { __disable_irq(); }
static void delay_ms(const int ms) { delay(ms); }
// Tasks, called from idle()
static void idletask();
// Reset
static uint8_t get_reset_source();
static void clear_reset_source() {}
// Free SRAM
static int freeMemory() { return ::freeMemory(); }
//
// ADC Methods
//
static uint16_t adc_result;
// Called by Temperature::init once at startup
static void adc_init() {}
// Called by Temperature::init for each sensor at startup
static void adc_enable(const uint8_t ch) {}
// Begin ADC sampling on the given channel. Called from Temperature::isr!
static void adc_start(const uint8_t ch) { adc_result = analogRead(ch); }
// Is the ADC ready for reading?
static bool adc_ready() { return true; }
// The current value of the ADC register
static uint16_t adc_value() { return adc_result; }
/**
* Set the PWM duty cycle for the pin to the given value.
* No inverting the duty cycle in this HAL.
* No changing the maximum size of the provided value to enable finer PWM duty control in this HAL.
*/
static void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) {
analogWrite(pin, v);
}
};

819
src/HAL/DUE/HAL_SPI.cpp Normal file
View File

@ -0,0 +1,819 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Software SPI functions originally from Arduino Sd2Card Library
* Copyright (c) 2009 by William Greiman
*
* Completely rewritten and tuned by Eduardo José Tagle in 2017/2018
* in ARM thumb2 inline assembler and tuned for maximum speed and performance
* allowing SPI clocks of up to 12 Mhz to increase SD card read/write performance
*/
/**
* HAL for Arduino Due and compatible (SAM3X8E)
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "../shared/Delay.h"
// ------------------------
// Public functions
// ------------------------
#if EITHER(DUE_SOFTWARE_SPI, FORCE_SOFT_SPI)
// ------------------------
// Software SPI
// ------------------------
// Make sure GCC optimizes this file.
// Note that this line triggers a bug in GCC which is fixed by casting.
// See the note below.
#pragma GCC optimize (3)
typedef uint8_t (*pfnSpiTransfer)(uint8_t b);
typedef void (*pfnSpiRxBlock)(uint8_t *buf, uint32_t nbyte);
typedef void (*pfnSpiTxBlock)(const uint8_t *buf, uint32_t nbyte);
/* ---------------- Macros to be able to access definitions from asm */
#define _PORT(IO) DIO ## IO ## _WPORT
#define _PIN_MASK(IO) MASK(DIO ## IO ## _PIN)
#define _PIN_SHIFT(IO) DIO ## IO ## _PIN
#define PORT(IO) _PORT(IO)
#define PIN_MASK(IO) _PIN_MASK(IO)
#define PIN_SHIFT(IO) _PIN_SHIFT(IO)
// run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static uint8_t spiTransferTx0(uint8_t bout) { // using Mode 0
uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t idx = 0;
/* Negate bout, as the assembler requires a negated value */
bout = ~bout;
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
/* Bit 7 */
A("ubfx %[idx],%[txval],#7,#1") /* Place bit 7 in bit 0 of idx*/
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#6,#1") /* Place bit 6 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 6 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#5,#1") /* Place bit 5 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 5 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#4,#1") /* Place bit 4 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 4 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#3,#1") /* Place bit 3 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 3 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#2,#1") /* Place bit 2 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 2 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#1,#1") /* Place bit 1 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 1 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[idx],%[txval],#0,#1") /* Place bit 0 in bit 0 of idx*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 0 */
A("str %[mosi_mask],[%[mosi_port], %[idx],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("nop") /* Result will be 0 */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
: [idx]"+r"( idx )
: [txval]"r"( bout ) ,
[mosi_mask]"r"( MOSI_MASK ),
[mosi_port]"r"( MOSI_PORT_PLUS30 ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
return 0;
}
// Calculates the bit band alias address and returns a pointer address to word.
// addr: The byte address of bitbanding bit.
// bit: The bit position of bitbanding bit.
#define BITBAND_ADDRESS(addr, bit) \
(((uint32_t)(addr) & 0xF0000000) + 0x02000000 + ((uint32_t)(addr)&0xFFFFF)*32 + (bit)*4)
// run at ~8 .. ~10Mhz - Rx version (Tx line not altered)
static uint8_t spiTransferRx0(uint8_t) { // using Mode 0
uint32_t bin = 0;
uint32_t work = 0;
uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
/* bit 7 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#7,#1") /* Store read bit as the bit 7 */
/* bit 6 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#6,#1") /* Store read bit as the bit 6 */
/* bit 5 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#5,#1") /* Store read bit as the bit 5 */
/* bit 4 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#4,#1") /* Store read bit as the bit 4 */
/* bit 3 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#3,#1") /* Store read bit as the bit 3 */
/* bit 2 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#2,#1") /* Store read bit as the bit 2 */
/* bit 1 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#1,#1") /* Store read bit as the bit 1 */
/* bit 0 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */
: [bin]"+r"(bin),
[work]"+r"(work)
: [bitband_miso_port]"r"( BITBAND_MISO_PORT ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
return bin;
}
// run at ~4Mhz
static uint8_t spiTransfer1(uint8_t b) { // using Mode 0
int bits = 8;
do {
WRITE(SD_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time
WRITE(SD_SCK_PIN, HIGH);
DELAY_NS(125); // 10 cycles @ 84mhz
b |= (READ(SD_MISO_PIN) != 0);
WRITE(SD_SCK_PIN, LOW);
DELAY_NS(125); // 10 cycles @ 84mhz
} while (--bits);
return b;
}
// all the others
static uint16_t spiDelayNS = 4000; // 4000ns => 125khz
static uint8_t spiTransferX(uint8_t b) { // using Mode 0
int bits = 8;
do {
WRITE(SD_MOSI_PIN, b & 0x80);
b <<= 1; // little setup time
WRITE(SD_SCK_PIN, HIGH);
DELAY_NS(spiDelayNS);
b |= (READ(SD_MISO_PIN) != 0);
WRITE(SD_SCK_PIN, LOW);
DELAY_NS(spiDelayNS);
} while (--bits);
return b;
}
// Pointers to generic functions for byte transfers
/**
* Note: The cast is unnecessary, but without it, this file triggers a GCC 4.8.3-2014 bug.
* Later GCC versions do not have this problem, but at this time (May 2018) Arduino still
* uses that buggy and obsolete GCC version!!
*/
static pfnSpiTransfer spiTransferRx = (pfnSpiTransfer)spiTransferX;
static pfnSpiTransfer spiTransferTx = (pfnSpiTransfer)spiTransferX;
// Block transfers run at ~8 .. ~10Mhz - Tx version (Rx data discarded)
static void spiTxBlock0(const uint8_t *ptr, uint32_t todo) {
uint32_t MOSI_PORT_PLUS30 = ((uint32_t) PORT(SD_MOSI_PIN)) + 0x30; /* SODR of port */
uint32_t MOSI_MASK = PIN_MASK(SD_MOSI_PIN);
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
uint32_t work = 0;
uint32_t txval = 0;
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("loop%=")
A("ldrb.w %[txval], [%[ptr]], #1") /* Load value to send, increment buffer */
A("mvn %[txval],%[txval]") /* Negate value */
/* Bit 7 */
A("ubfx %[work],%[txval],#7,#1") /* Place bit 7 in bit 0 of work*/
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#6,#1") /* Place bit 6 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 6 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#5,#1") /* Place bit 5 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 5 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#4,#1") /* Place bit 4 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 4 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#3,#1") /* Place bit 3 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 3 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#2,#1") /* Place bit 2 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 2 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#1,#1") /* Place bit 1 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 1 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ubfx %[work],%[txval],#0,#1") /* Place bit 0 in bit 0 of work*/
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
/* Bit 0 */
A("str %[mosi_mask],[%[mosi_port], %[work],LSL #2]") /* Access the proper SODR or CODR registers based on that bit */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("subs %[todo],#1") /* Decrement count of pending words to send, update status */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bne.n loop%=") /* Repeat until done */
: [ptr]"+r" ( ptr ) ,
[todo]"+r" ( todo ) ,
[work]"+r"( work ) ,
[txval]"+r"( txval )
: [mosi_mask]"r"( MOSI_MASK ),
[mosi_port]"r"( MOSI_PORT_PLUS30 ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
}
static void spiRxBlock0(uint8_t *ptr, uint32_t todo) {
uint32_t bin = 0;
uint32_t work = 0;
uint32_t BITBAND_MISO_PORT = BITBAND_ADDRESS( ((uint32_t)PORT(SD_MISO_PIN))+0x3C, PIN_SHIFT(SD_MISO_PIN)); /* PDSR of port in bitband area */
uint32_t SCK_PORT_PLUS30 = ((uint32_t) PORT(SD_SCK_PIN)) + 0x30; /* SODR of port */
uint32_t SCK_MASK = PIN_MASK(SD_SCK_PIN);
/* The software SPI routine */
__asm__ __volatile__(
A(".syntax unified") // is to prevent CM0,CM1 non-unified syntax
L("loop%=")
/* bit 7 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#7,#1") /* Store read bit as the bit 7 */
/* bit 6 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#6,#1") /* Store read bit as the bit 6 */
/* bit 5 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#5,#1") /* Store read bit as the bit 5 */
/* bit 4 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#4,#1") /* Store read bit as the bit 4 */
/* bit 3 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#3,#1") /* Store read bit as the bit 3 */
/* bit 2 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#2,#1") /* Store read bit as the bit 2 */
/* bit 1 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#1,#1") /* Store read bit as the bit 1 */
/* bit 0 */
A("str %[sck_mask],[%[sck_port]]") /* SODR */
A("ldr %[work],[%[bitband_miso_port]]") /* PDSR on bitband area for required bit: work will be 1 or 0 based on port */
A("str %[sck_mask],[%[sck_port],#0x4]") /* CODR */
A("bfi %[bin],%[work],#0,#1") /* Store read bit as the bit 0 */
A("subs %[todo],#1") /* Decrement count of pending words to send, update status */
A("strb.w %[bin], [%[ptr]], #1") /* Store read value into buffer, increment buffer pointer */
A("bne.n loop%=") /* Repeat until done */
: [ptr]"+r"(ptr),
[todo]"+r"(todo),
[bin]"+r"(bin),
[work]"+r"(work)
: [bitband_miso_port]"r"( BITBAND_MISO_PORT ),
[sck_mask]"r"( SCK_MASK ),
[sck_port]"r"( SCK_PORT_PLUS30 )
: "cc"
);
}
static void spiTxBlockX(const uint8_t *buf, uint32_t todo) {
do {
(void)spiTransferTx(*buf++);
} while (--todo);
}
static void spiRxBlockX(uint8_t *buf, uint32_t todo) {
do {
*buf++ = spiTransferRx(0xFF);
} while (--todo);
}
// Pointers to generic functions for block transfers
static pfnSpiTxBlock spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
static pfnSpiRxBlock spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
#if MB(ALLIGATOR)
#define _SS_WRITE(S) WRITE(SD_SS_PIN, S)
#else
#define _SS_WRITE(S) NOOP
#endif
void spiBegin() {
SET_OUTPUT(SD_SS_PIN);
_SS_WRITE(HIGH);
SET_OUTPUT(SD_SCK_PIN);
SET_INPUT(SD_MISO_PIN);
SET_OUTPUT(SD_MOSI_PIN);
}
uint8_t spiRec() {
_SS_WRITE(LOW);
WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
uint8_t b = spiTransferRx(0xFF);
_SS_WRITE(HIGH);
return b;
}
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (nbyte) {
_SS_WRITE(LOW);
WRITE(SD_MOSI_PIN, HIGH); // Output 1s 1
spiRxBlock(buf, nbyte);
_SS_WRITE(HIGH);
}
}
void spiSend(uint8_t b) {
_SS_WRITE(LOW);
(void)spiTransferTx(b);
_SS_WRITE(HIGH);
}
void spiSendBlock(uint8_t token, const uint8_t *buf) {
_SS_WRITE(LOW);
(void)spiTransferTx(token);
spiTxBlock(buf, 512);
_SS_WRITE(HIGH);
}
/**
* spiRate should be
* 0 : 8 - 10 MHz
* 1 : 4 - 5 MHz
* 2 : 2 - 2.5 MHz
* 3 : 1 - 1.25 MHz
* 4 : 500 - 625 kHz
* 5 : 250 - 312 kHz
* 6 : 125 - 156 kHz
*/
void spiInit(uint8_t spiRate) {
switch (spiRate) {
case 0:
spiTransferTx = (pfnSpiTransfer)spiTransferTx0;
spiTransferRx = (pfnSpiTransfer)spiTransferRx0;
spiTxBlock = (pfnSpiTxBlock)spiTxBlock0;
spiRxBlock = (pfnSpiRxBlock)spiRxBlock0;
break;
case 1:
spiTransferTx = (pfnSpiTransfer)spiTransfer1;
spiTransferRx = (pfnSpiTransfer)spiTransfer1;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break;
default:
spiDelayNS = 4000 >> (6 - spiRate); // spiRate of 2 gives the maximum error with current CPU
spiTransferTx = (pfnSpiTransfer)spiTransferX;
spiTransferRx = (pfnSpiTransfer)spiTransferX;
spiTxBlock = (pfnSpiTxBlock)spiTxBlockX;
spiRxBlock = (pfnSpiRxBlock)spiRxBlockX;
break;
}
_SS_WRITE(HIGH);
WRITE(SD_MOSI_PIN, HIGH);
WRITE(SD_SCK_PIN, LOW);
}
/** Begin SPI transaction, set clock, bit order, data mode */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
// TODO: to be implemented
}
#pragma GCC reset_options
#else // !SOFTWARE_SPI
#define WHILE_TX(N) while ((SPI0->SPI_SR & SPI_SR_TDRE) == (N))
#define WHILE_RX(N) while ((SPI0->SPI_SR & SPI_SR_RDRF) == (N))
#define FLUSH_TX() do{ WHILE_RX(1) SPI0->SPI_RDR; }while(0)
#if MB(ALLIGATOR)
// slave selects controlled by SPI controller
// doesn't support changing SPI speeds for SD card
// ------------------------
// hardware SPI
// ------------------------
static bool spiInitialized = false;
void spiInit(uint8_t spiRate) {
if (spiInitialized) return;
// 8.4 MHz, 4 MHz, 2 MHz, 1 MHz, 0.5 MHz, 0.329 MHz, 0.329 MHz
constexpr int spiDivider[] = { 10, 21, 42, 84, 168, 255, 255 };
if (spiRate > 6) spiRate = 1;
// Set SPI mode 1, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN_DAC,
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
// Set SPI mode 0, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN_EEPROM1, SPI_CSR_NCPHA |
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
// Set SPI mode 0, clock, select not active after transfer, with delay between transfers
SPI_ConfigureNPCS(SPI0, SPI_CHAN, SPI_CSR_NCPHA |
SPI_CSR_CSAAT | SPI_CSR_SCBR(spiDivider[spiRate]) |
SPI_CSR_DLYBCT(1));
SPI_Enable(SPI0);
spiInitialized = true;
}
void spiBegin() {
if (spiInitialized) return;
// Configure SPI pins
PIO_Configure(
g_APinDescription[SD_SCK_PIN].pPort,
g_APinDescription[SD_SCK_PIN].ulPinType,
g_APinDescription[SD_SCK_PIN].ulPin,
g_APinDescription[SD_SCK_PIN].ulPinConfiguration);
PIO_Configure(
g_APinDescription[SD_MOSI_PIN].pPort,
g_APinDescription[SD_MOSI_PIN].ulPinType,
g_APinDescription[SD_MOSI_PIN].ulPin,
g_APinDescription[SD_MOSI_PIN].ulPinConfiguration);
PIO_Configure(
g_APinDescription[SD_MISO_PIN].pPort,
g_APinDescription[SD_MISO_PIN].ulPinType,
g_APinDescription[SD_MISO_PIN].ulPin,
g_APinDescription[SD_MISO_PIN].ulPinConfiguration);
// set master mode, peripheral select, fault detection
SPI_Configure(SPI0, ID_SPI0, SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS);
SPI_Enable(SPI0);
SET_OUTPUT(DAC0_SYNC_PIN);
#if HAS_MULTI_EXTRUDER
OUT_WRITE(DAC1_SYNC_PIN, HIGH);
#endif
WRITE(DAC0_SYNC_PIN, HIGH);
OUT_WRITE(SPI_EEPROM1_CS_PIN, HIGH);
OUT_WRITE(SPI_EEPROM2_CS_PIN, HIGH);
OUT_WRITE(SPI_FLASH_CS_PIN, HIGH);
WRITE(SD_SS_PIN, HIGH);
OUT_WRITE(SDSS, LOW);
PIO_Configure(
g_APinDescription[SPI_PIN].pPort,
g_APinDescription[SPI_PIN].ulPinType,
g_APinDescription[SPI_PIN].ulPin,
g_APinDescription[SPI_PIN].ulPinConfiguration
);
spiInit(1);
}
// Read single byte from SPI
uint8_t spiRec() {
// write dummy byte with address and end transmission flag
SPI0->SPI_TDR = 0x000000FF | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
WHILE_TX(0);
WHILE_RX(0);
//DELAY_US(1U);
return SPI0->SPI_RDR;
}
uint8_t spiRec(uint32_t chan) {
WHILE_TX(0);
FLUSH_RX();
// write dummy byte with address and end transmission flag
SPI0->SPI_TDR = 0x000000FF | SPI_PCS(chan) | SPI_TDR_LASTXFER;
WHILE_RX(0);
return SPI0->SPI_RDR;
}
// Read from SPI into buffer
void spiRead(uint8_t *buf, uint16_t nbyte) {
if (!nbyte) return;
--nbyte;
for (int i = 0; i < nbyte; i++) {
//WHILE_TX(0);
SPI0->SPI_TDR = 0x000000FF | SPI_PCS(SPI_CHAN);
WHILE_RX(0);
buf[i] = SPI0->SPI_RDR;
//DELAY_US(1U);
}
buf[nbyte] = spiRec();
}
// Write single byte to SPI
void spiSend(const byte b) {
// write byte with address and end transmission flag
SPI0->SPI_TDR = (uint32_t)b | SPI_PCS(SPI_CHAN) | SPI_TDR_LASTXFER;
WHILE_TX(0);
WHILE_RX(0);
SPI0->SPI_RDR;
//DELAY_US(1U);
}
void spiSend(const uint8_t *buf, size_t nbyte) {
if (!nbyte) return;
--nbyte;
for (size_t i = 0; i < nbyte; i++) {
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
WHILE_RX(0);
SPI0->SPI_RDR;
//DELAY_US(1U);
}
spiSend(buf[nbyte]);
}
void spiSend(uint32_t chan, byte b) {
WHILE_TX(0);
// write byte with address and end transmission flag
SPI0->SPI_TDR = (uint32_t)b | SPI_PCS(chan) | SPI_TDR_LASTXFER;
WHILE_RX(0);
FLUSH_RX();
}
void spiSend(uint32_t chan, const uint8_t *buf, size_t nbyte) {
if (!nbyte) return;
--nbyte;
for (size_t i = 0; i < nbyte; i++) {
WHILE_TX(0);
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(chan);
WHILE_RX(0);
FLUSH_RX();
}
spiSend(chan, buf[nbyte]);
}
// Write from buffer to SPI
void spiSendBlock(uint8_t token, const uint8_t *buf) {
SPI0->SPI_TDR = (uint32_t)token | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
//WHILE_RX(0);
//SPI0->SPI_RDR;
for (int i = 0; i < 511; i++) {
SPI0->SPI_TDR = (uint32_t)buf[i] | SPI_PCS(SPI_CHAN);
WHILE_TX(0);
WHILE_RX(0);
SPI0->SPI_RDR;
//DELAY_US(1U);
}
spiSend(buf[511]);
}
/** Begin SPI transaction, set clock, bit order, data mode */
void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
// TODO: to be implemented
}
#else // U8G compatible hardware SPI
#define SPI_MODE_0_DUE_HW 2 // DUE CPHA control bit is inverted
#define SPI_MODE_1_DUE_HW 3
#define SPI_MODE_2_DUE_HW 0
#define SPI_MODE_3_DUE_HW 1
/**
* The DUE SPI controller is set up so the upper word of the longword
* written to the transmit data register selects which SPI Chip Select
* Register is used. This allows different streams to have different SPI
* settings.
*
* In practice it's spooky. Some combinations hang the system, while others
* upset the peripheral device.
*
* SPI mode should be the same for all streams. The FYSETC_MINI_12864 gets
* upset if the clock phase changes after chip select goes active.
*
* SPI_CSR_CSAAT should be set for all streams. If not the WHILE_TX(0)
* macro returns immediately which can result in the SPI chip select going
* inactive before all the data has been sent.
*
* The TMC2130 library uses SPI0->SPI_CSR[3].
*
* The U8G hardware SPI uses SPI0->SPI_CSR[0]. The system hangs and/or the
* FYSETC_MINI_12864 gets upset if lower baud rates are used and the SD card
* is inserted or removed.
*
* The SD card uses SPI0->SPI_CSR[3]. Efforts were made to use [1] and [2]
* but they all resulted in hangs or garbage on the LCD.
*
* The SPI controlled chip selects are NOT enabled in the GPIO controller.
* The application must control the chip select.
*
* All of the above can be avoided by defining FORCE_SOFT_SPI to force the
* display to use software SPI.
*/
void spiInit(uint8_t spiRate=6) { // Default to slowest rate if not specified)
// Also sets U8G SPI rate to 4MHz and the SPI mode to 3
// 8.4 MHz, 4 MHz, 2 MHz, 1 MHz, 0.5 MHz, 0.329 MHz, 0.329 MHz
constexpr int spiDivider[] = { 10, 21, 42, 84, 168, 255, 255 };
if (spiRate > 6) spiRate = 1;
// Enable PIOA and SPI0
REG_PMC_PCER0 = (1UL << ID_PIOA) | (1UL << ID_SPI0);
// Disable PIO on A26 and A27
REG_PIOA_PDR = 0x0C000000;
OUT_WRITE(SDSS, HIGH);
// Reset SPI0 (from sam lib)
SPI0->SPI_CR = SPI_CR_SPIDIS;
SPI0->SPI_CR = SPI_CR_SWRST;
SPI0->SPI_CR = SPI_CR_SWRST;
SPI0->SPI_CR = SPI_CR_SPIEN;
// TMC2103 compatible setup
// Master mode, no fault detection, PCS bits in data written to TDR select CSR register
SPI0->SPI_MR = SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS;
// SPI mode 3, 8 Bit data transfer, baud rate
SPI0->SPI_CSR[3] = SPI_CSR_SCBR(spiDivider[spiRate]) | SPI_CSR_CSAAT | SPI_MODE_3_DUE_HW; // use same CSR as TMC2130
SPI0->SPI_CSR[0] = SPI_CSR_SCBR(spiDivider[1]) | SPI_CSR_CSAAT | SPI_MODE_3_DUE_HW; // U8G default to 4MHz
}
void spiBegin() { spiInit(); }
static uint8_t spiTransfer(uint8_t data) {
WHILE_TX(0);
SPI0->SPI_TDR = (uint32_t)data | 0x00070000UL; // Add TMC2130 PCS bits to every byte (use SPI0->SPI_CSR[3])
WHILE_TX(0);
WHILE_RX(0);
return SPI0->SPI_RDR;
}
uint8_t spiRec() { return (uint8_t)spiTransfer(0xFF); }
void spiRead(uint8_t *buf, uint16_t nbyte) {
for (int i = 0; i < nbyte; i++)
buf[i] = spiTransfer(0xFF);
}
void spiSend(uint8_t data) { spiTransfer(data); }
void spiSend(const uint8_t *buf, size_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++)
spiTransfer(buf[i]);
}
void spiSendBlock(uint8_t token, const uint8_t *buf) {
spiTransfer(token);
for (uint16_t i = 0; i < 512; i++)
spiTransfer(buf[i]);
}
#endif // !ALLIGATOR
#endif // !SOFTWARE_SPI
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,98 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* InterruptVectors_Due.cpp - This module relocates the Interrupt vector table to SRAM,
* allowing to register new interrupt handlers at runtime. Specially valuable and needed
* because Arduino runtime allocates some interrupt handlers that we NEED to override to
* properly support extended functionality, as for example, USB host or USB device (MSD, MTP)
* and custom serial port handlers, and we don't actually want to modify and/or recompile the
* Arduino runtime. We just want to run as much as possible on Stock Arduino
*
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
#include "InterruptVectors.h"
/* The relocated Exception/Interrupt Table - According to the ARM
reference manual, alignment to 128 bytes should suffice, but in
practice, we need alignment to 256 bytes to make this work in all
cases */
__attribute__ ((aligned(256)))
static DeviceVectors ram_tab = { nullptr };
/**
* This function checks if the exception/interrupt table is already in SRAM or not.
* If it is not, then it copies the ROM table to the SRAM and relocates the table
* by reprogramming the NVIC registers
*/
static pfnISR_Handler* get_relocated_table_addr() {
// Get the address of the interrupt/exception table
uint32_t isrtab = SCB->VTOR;
// If already relocated, we are done!
if (isrtab >= IRAM0_ADDR)
return (pfnISR_Handler*)isrtab;
// Get the address of the table stored in FLASH
const pfnISR_Handler* romtab = (const pfnISR_Handler*)isrtab;
// Copy it to SRAM
memcpy(&ram_tab, romtab, sizeof(ram_tab));
// Disable global interrupts
CRITICAL_SECTION_START();
// Set the vector table base address to the SRAM copy
SCB->VTOR = (uint32_t)(&ram_tab);
// Reenable interrupts
CRITICAL_SECTION_END();
// Return the address of the table
return (pfnISR_Handler*)(&ram_tab);
}
pfnISR_Handler install_isr(IRQn_Type irq, pfnISR_Handler newHandler) {
// Get the address of the relocated table
pfnISR_Handler *isrtab = get_relocated_table_addr();
// Disable global interrupts
CRITICAL_SECTION_START();
// Get the original handler
pfnISR_Handler oldHandler = isrtab[irq + 16];
// Install the new one
isrtab[irq + 16] = newHandler;
// Reenable interrupts
CRITICAL_SECTION_END();
// Return the original one
return oldHandler;
}
#endif

View File

@ -0,0 +1,45 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* InterruptVectors_Due.h
*
* This module relocates the Interrupt vector table to SRAM, allowing new
* interrupt handlers to be added at runtime. This is required because the
* Arduino runtime steals interrupt handlers that Marlin MUST use to support
* extended functionality such as USB hosts and USB devices (MSD, MTP) and
* custom serial port handlers. Rather than modifying and/or recompiling the
* Arduino runtime, We just want to run as much as possible on Stock Arduino.
*
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
*/
#ifdef ARDUINO_ARCH_SAM
// ISR handler type
typedef void (*pfnISR_Handler)();
// Install a new interrupt vector handler for the given irq, returning the old one
pfnISR_Handler install_isr(IRQn_Type irq, pfnISR_Handler newHandler);
#endif // ARDUINO_ARCH_SAM

26
src/HAL/DUE/MarlinSPI.h Normal file
View File

@ -0,0 +1,26 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <SPI.h>
using MarlinSPI = SPIClass;

View File

@ -0,0 +1,494 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
* Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "MarlinSerial.h"
#include "InterruptVectors.h"
#include "../../MarlinCore.h"
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_r MarlinSerial<Cfg>::rx_buffer = { 0, 0, { 0 } };
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_t MarlinSerial<Cfg>::tx_buffer = { 0 };
template<typename Cfg> bool MarlinSerial<Cfg>::_written = false;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::xon_xoff_state = MarlinSerial<Cfg>::XON_XOFF_CHAR_SENT | MarlinSerial<Cfg>::XON_CHAR;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_dropped_bytes = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_buffer_overruns = 0;
template<typename Cfg> uint8_t MarlinSerial<Cfg>::rx_framing_errors = 0;
template<typename Cfg> typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::rx_max_enqueued = 0;
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() asm volatile("": : :"memory");
#include "../../feature/e_parser.h"
// (called with RX interrupts disabled)
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::store_rxd_char() {
static EmergencyParser::State emergency_state; // = EP_RESET
// Get the tail - Nothing can alter its value while we are at this ISR
const ring_buffer_pos_t t = rx_buffer.tail;
// Get the head pointer
ring_buffer_pos_t h = rx_buffer.head;
// Get the next element
ring_buffer_pos_t i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
uint8_t c = HWUART->UART_RHR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the RX FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Calculate count of bytes stored into the RX buffer
// Keep track of the maximum count of enqueued bytes
if (Cfg::MAX_RX_QUEUED) NOLESS(rx_max_enqueued, rx_count);
if (Cfg::XONOFF) {
// If the last char that was sent was an XON
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XON_CHAR) {
// Bytes stored into the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// If over 12.5% of RX buffer capacity, send XOFF before running out of
// RX buffer space .. 325 bytes @ 250kbits/s needed to let the host react
// and stop sending bytes. This translates to 13mS propagation time.
if (rx_count >= (Cfg::RX_SIZE) / 8) {
// At this point, definitely no TX interrupt was executing, since the TX isr can't be preempted.
// Don't enable the TX interrupt here as a means to trigger the XOFF char, because if it happens
// to be in the middle of trying to disable the RX interrupt in the main program, eventually the
// enabling of the TX interrupt could be undone. The ONLY reliable thing this can do to ensure
// the sending of the XOFF char is to send it HERE AND NOW.
// About to send the XOFF char
xon_xoff_state = XOFF_CHAR | XON_XOFF_CHAR_SENT;
// Wait until the TX register becomes empty and send it - Here there could be a problem
// - While waiting for the TX register to empty, the RX register could receive a new
// character. This must also handle that situation!
uint32_t status;
while (!((status = HWUART->UART_SR) & UART_SR_TXRDY)) {
if (status & UART_SR_RXRDY) {
// We received a char while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = HWUART->UART_RHR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
HWUART->UART_THR = XOFF_CHAR;
// At this point there could be a race condition between the write() function
// and this sending of the XOFF char. This interrupt could happen between the
// wait to be empty TX buffer loop and the actual write of the character. Since
// the TX buffer is full because it's sending the XOFF char, the only way to be
// sure the write() function will succeed is to wait for the XOFF char to be
// completely sent. Since an extra character could be received during the wait
// it must also be handled!
while (!((status = HWUART->UART_SR) & UART_SR_TXRDY)) {
if (status & UART_SR_RXRDY) {
// A char arrived while waiting for the TX buffer to be empty - Receive and process it!
i = (ring_buffer_pos_t)(h + 1) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// Read the character from the USART
c = HWUART->UART_RHR;
if (Cfg::EMERGENCYPARSER) emergency_parser.update(emergency_state, c);
// If the character is to be stored at the index just before the tail
// (such that the head would advance to the current tail), the FIFO is
// full, so don't write the character or advance the head.
if (i != t) {
rx_buffer.buffer[h] = c;
h = i;
}
else if (Cfg::DROPPED_RX && !++rx_dropped_bytes)
--rx_dropped_bytes;
}
sw_barrier();
}
// At this point everything is ready. The write() function won't
// have any issues writing to the UART TX register if it needs to!
}
}
}
// Store the new head value
rx_buffer.head = h;
}
template<typename Cfg>
FORCE_INLINE void MarlinSerial<Cfg>::_tx_thr_empty_irq() {
if (Cfg::TX_SIZE > 0) {
// Read positions
uint8_t t = tx_buffer.tail;
const uint8_t h = tx_buffer.head;
if (Cfg::XONOFF) {
// If an XON char is pending to be sent, do it now
if (xon_xoff_state == XON_CHAR) {
// Send the character
HWUART->UART_THR = XON_CHAR;
// Remember we sent it.
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
// If nothing else to transmit, just disable TX interrupts.
if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
return;
}
}
// If nothing to transmit, just disable TX interrupts. This could
// happen as the result of the non atomicity of the disabling of RX
// interrupts that could end reenabling TX interrupts as a side effect.
if (h == t) {
HWUART->UART_IDR = UART_IDR_TXRDY;
return;
}
// There is something to TX, Send the next byte
const uint8_t c = tx_buffer.buffer[t];
t = (t + 1) & (Cfg::TX_SIZE - 1);
HWUART->UART_THR = c;
tx_buffer.tail = t;
// Disable interrupts if there is nothing to transmit following this byte
if (h == t) HWUART->UART_IDR = UART_IDR_TXRDY;
}
}
template<typename Cfg>
void MarlinSerial<Cfg>::UART_ISR() {
const uint32_t status = HWUART->UART_SR;
// Data received?
if (status & UART_SR_RXRDY) store_rxd_char();
if (Cfg::TX_SIZE > 0) {
// Something to send, and TX interrupts are enabled (meaning something to send)?
if ((status & UART_SR_TXRDY) && (HWUART->UART_IMR & UART_IMR_TXRDY)) _tx_thr_empty_irq();
}
// Acknowledge errors
if ((status & UART_SR_OVRE) || (status & UART_SR_FRAME)) {
if (Cfg::DROPPED_RX && (status & UART_SR_OVRE) && !++rx_dropped_bytes) --rx_dropped_bytes;
if (Cfg::RX_OVERRUNS && (status & UART_SR_OVRE) && !++rx_buffer_overruns) --rx_buffer_overruns;
if (Cfg::RX_FRAMING_ERRORS && (status & UART_SR_FRAME) && !++rx_framing_errors) --rx_framing_errors;
// TODO: error reporting outside ISR
HWUART->UART_CR = UART_CR_RSTSTA;
}
}
// Public Methods
template<typename Cfg>
void MarlinSerial<Cfg>::begin(const long baud_setting) {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( HWUART_IRQ );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable clock
pmc_disable_periph_clk( HWUART_IRQ_ID );
// Configure PMC
pmc_enable_periph_clk( HWUART_IRQ_ID );
// Disable PDC channel
HWUART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
HWUART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
HWUART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO;
// Configure baudrate (asynchronous, no oversampling)
HWUART->UART_BRGR = (SystemCoreClock / (baud_setting << 4));
// Configure interrupts
HWUART->UART_IDR = 0xFFFFFFFF;
HWUART->UART_IER = UART_IER_RXRDY | UART_IER_OVRE | UART_IER_FRAME;
// Install interrupt handler
install_isr(HWUART_IRQ, UART_ISR);
// Configure priority. We need a very high priority to avoid losing characters
// and we need to be able to preempt the Stepper ISR and everything else!
// (this could probably be fixed by using DMA with the Serial port)
NVIC_SetPriority(HWUART_IRQ, 1);
// Enable UART interrupt in NVIC
NVIC_EnableIRQ(HWUART_IRQ);
// Enable receiver and transmitter
HWUART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
if (Cfg::TX_SIZE > 0) _written = false;
}
template<typename Cfg>
void MarlinSerial<Cfg>::end() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( HWUART_IRQ );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
pmc_disable_periph_clk( HWUART_IRQ_ID );
}
template<typename Cfg>
int MarlinSerial<Cfg>::peek() {
const int v = rx_buffer.head == rx_buffer.tail ? -1 : rx_buffer.buffer[rx_buffer.tail];
return v;
}
template<typename Cfg>
int MarlinSerial<Cfg>::read() {
const ring_buffer_pos_t h = rx_buffer.head;
ring_buffer_pos_t t = rx_buffer.tail;
if (h == t) return -1;
int v = rx_buffer.buffer[t];
t = (ring_buffer_pos_t)(t + 1) & (Cfg::RX_SIZE - 1);
// Advance tail
rx_buffer.tail = t;
if (Cfg::XONOFF) {
// If the XOFF char was sent, or about to be sent...
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
// Get count of bytes in the RX buffer
const ring_buffer_pos_t rx_count = (ring_buffer_pos_t)(h - t) & (ring_buffer_pos_t)(Cfg::RX_SIZE - 1);
// When below 10% of RX buffer capacity, send XON before running out of RX buffer bytes
if (rx_count < (Cfg::RX_SIZE) / 10) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX isr.
HWUART->UART_IER = UART_IER_TXRDY;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
HWUART->UART_THR = XON_CHAR;
}
}
}
}
return v;
}
template<typename Cfg>
typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::available() {
const ring_buffer_pos_t h = rx_buffer.head, t = rx_buffer.tail;
return (ring_buffer_pos_t)(Cfg::RX_SIZE + h - t) & (Cfg::RX_SIZE - 1);
}
template<typename Cfg>
void MarlinSerial<Cfg>::flush() {
rx_buffer.tail = rx_buffer.head;
if (Cfg::XONOFF) {
if ((xon_xoff_state & XON_XOFF_CHAR_MASK) == XOFF_CHAR) {
if (Cfg::TX_SIZE > 0) {
// Signal we want an XON character to be sent.
xon_xoff_state = XON_CHAR;
// Enable TX isr.
HWUART->UART_IER = UART_IER_TXRDY;
}
else {
// If not using TX interrupts, we must send the XON char now
xon_xoff_state = XON_CHAR | XON_XOFF_CHAR_SENT;
while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
HWUART->UART_THR = XON_CHAR;
}
}
}
}
template<typename Cfg>
size_t MarlinSerial<Cfg>::write(const uint8_t c) {
_written = true;
if (Cfg::TX_SIZE == 0) {
while (!(HWUART->UART_SR & UART_SR_TXRDY)) sw_barrier();
HWUART->UART_THR = c;
}
else {
// If the TX interrupts are disabled and the data register
// is empty, just write the byte to the data register and
// be done. This shortcut helps significantly improve the
// effective datarate at high (>500kbit/s) bitrates, where
// interrupt overhead becomes a slowdown.
// Yes, there is a race condition between the sending of the
// XOFF char at the RX isr, but it is properly handled there
if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
HWUART->UART_THR = c;
return 1;
}
const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!hal.isr_state()) {
// Make room by polling if it is possible to transmit, and do so!
while (i == tx_buffer.tail) {
// If we can transmit another byte, do it.
if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq();
// Make sure compiler rereads tx_buffer.tail
sw_barrier();
}
}
else {
// Interrupts are enabled, just wait until there is space
while (i == tx_buffer.tail) sw_barrier();
}
// Store new char. head is always safe to move
tx_buffer.buffer[tx_buffer.head] = c;
tx_buffer.head = i;
// Enable TX isr - Non atomic, but it will eventually enable TX isr
HWUART->UART_IER = UART_IER_TXRDY;
}
return 1;
}
template<typename Cfg>
void MarlinSerial<Cfg>::flushTX() {
// TX
if (Cfg::TX_SIZE == 0) {
// No bytes written, no need to flush. This special case is needed since there's
// no way to force the TXC (transmit complete) bit to 1 during initialization.
if (!_written) return;
// Wait until everything was transmitted
while (!(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
else {
// If we have never written a byte, no need to flush. This special
// case is needed since there is no way to force the TXC (transmit
// complete) bit to 1 during initialization
if (!_written) return;
// If global interrupts are disabled (as the result of being called from an ISR)...
if (!hal.isr_state()) {
// Wait until everything was transmitted - We must do polling, as interrupts are disabled
while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) {
// If there is more space, send an extra character
if (HWUART->UART_SR & UART_SR_TXRDY) _tx_thr_empty_irq();
sw_barrier();
}
}
else {
// Wait until everything was transmitted
while (tx_buffer.head != tx_buffer.tail || !(HWUART->UART_SR & UART_SR_TXEMPTY)) sw_barrier();
}
// At this point nothing is queued anymore (DRIE is disabled) and
// the hardware finished transmission (TXC is set).
}
}
// If not using the USB port as serial port
#if defined(SERIAL_PORT) && SERIAL_PORT >= 0
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
MSerialT1 customizedSerial1(MarlinSerialCfg<SERIAL_PORT>::EMERGENCYPARSER);
#endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
MSerialT2 customizedSerial2(MarlinSerialCfg<SERIAL_PORT_2>::EMERGENCYPARSER);
#endif
#if defined(SERIAL_PORT_3) && SERIAL_PORT_3 >= 0
template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> >;
MSerialT3 customizedSerial3(MarlinSerialCfg<SERIAL_PORT_3>::EMERGENCYPARSER);
#endif
#endif // ARDUINO_ARCH_SAM

156
src/HAL/DUE/MarlinSerial.h Normal file
View File

@ -0,0 +1,156 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* MarlinSerial_Due.h - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
* Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved.
*/
#include <WString.h>
#include "../../inc/MarlinConfigPre.h"
#include "../../core/serial_hook.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
// 256 is the max limit due to uint8_t head and tail. Use only powers of 2. (...,16,32,64,128,256)
#ifndef RX_BUFFER_SIZE
#define RX_BUFFER_SIZE 128
#endif
#ifndef TX_BUFFER_SIZE
#define TX_BUFFER_SIZE 32
#endif
//#if ENABLED(SERIAL_XON_XOFF) && RX_BUFFER_SIZE < 1024
// #error "SERIAL_XON_XOFF requires RX_BUFFER_SIZE >= 1024 for reliable transfers without drops."
//#elif RX_BUFFER_SIZE && (RX_BUFFER_SIZE < 2 || !IS_POWER_OF_2(RX_BUFFER_SIZE))
// #error "RX_BUFFER_SIZE must be a power of 2 greater than 1."
//#elif TX_BUFFER_SIZE && (TX_BUFFER_SIZE < 2 || TX_BUFFER_SIZE > 256 || !IS_POWER_OF_2(TX_BUFFER_SIZE))
// #error "TX_BUFFER_SIZE must be 0, a power of 2 greater than 1, and no greater than 256."
//#endif
// Templated type selector
template<bool b, typename T, typename F> struct TypeSelector { typedef T type;} ;
template<typename T, typename F> struct TypeSelector<false, T, F> { typedef F type; };
// Templated structure wrapper
template<typename S, unsigned int addr> struct StructWrapper {
constexpr StructWrapper(int) {}
FORCE_INLINE S* operator->() const { return (S*)addr; }
};
template<typename Cfg>
class MarlinSerial {
protected:
// Information for all supported UARTs
static constexpr uint32_t BASES[] = {0x400E0800U, 0x40098000U, 0x4009C000U, 0x400A0000U, 0x400A4000U};
static constexpr IRQn_Type IRQS[] = { UART_IRQn, USART0_IRQn, USART1_IRQn, USART2_IRQn, USART3_IRQn};
static constexpr int IRQ_IDS[] = { ID_UART, ID_USART0, ID_USART1, ID_USART2, ID_USART3};
// Alias for shorter code
static constexpr StructWrapper<Uart,BASES[Cfg::PORT]> HWUART = 0;
static constexpr IRQn_Type HWUART_IRQ = IRQS[Cfg::PORT];
static constexpr int HWUART_IRQ_ID = IRQ_IDS[Cfg::PORT];
// Base size of type on buffer size
typedef typename TypeSelector<(Cfg::RX_SIZE>256), uint16_t, uint8_t>::type ring_buffer_pos_t;
struct ring_buffer_r {
volatile ring_buffer_pos_t head, tail;
unsigned char buffer[Cfg::RX_SIZE];
};
struct ring_buffer_t {
volatile uint8_t head, tail;
unsigned char buffer[Cfg::TX_SIZE];
};
static ring_buffer_r rx_buffer;
static ring_buffer_t tx_buffer;
static bool _written;
static constexpr uint8_t XON_XOFF_CHAR_SENT = 0x80, // XON / XOFF Character was sent
XON_XOFF_CHAR_MASK = 0x1F; // XON / XOFF character to send
// XON / XOFF character definitions
static constexpr uint8_t XON_CHAR = 17, XOFF_CHAR = 19;
static uint8_t xon_xoff_state,
rx_dropped_bytes,
rx_buffer_overruns,
rx_framing_errors;
static ring_buffer_pos_t rx_max_enqueued;
FORCE_INLINE static void store_rxd_char();
FORCE_INLINE static void _tx_thr_empty_irq();
static void UART_ISR();
public:
MarlinSerial() {};
static void begin(const long);
static void end();
static int peek();
static int read();
static void flush();
static ring_buffer_pos_t available();
static size_t write(const uint8_t c);
static void flushTX();
static bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
};
// Serial port configuration
template <uint8_t serial>
struct MarlinSerialCfg {
static constexpr int PORT = serial;
static constexpr unsigned int RX_SIZE = RX_BUFFER_SIZE;
static constexpr unsigned int TX_SIZE = TX_BUFFER_SIZE;
static constexpr bool XONOFF = ENABLED(SERIAL_XON_XOFF);
static constexpr bool EMERGENCYPARSER = ENABLED(EMERGENCY_PARSER);
static constexpr bool DROPPED_RX = ENABLED(SERIAL_STATS_DROPPED_RX);
static constexpr bool RX_OVERRUNS = ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS);
static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
static constexpr bool MAX_RX_QUEUED = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
};
#if defined(SERIAL_PORT) && SERIAL_PORT >= 0
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT1;
extern MSerialT1 customizedSerial1;
#endif
#if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
#if defined(SERIAL_PORT_3) && SERIAL_PORT_3 >= 0
typedef Serial1Class< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_3> > > MSerialT3;
extern MSerialT3 customizedSerial3;
#endif

View File

@ -0,0 +1,142 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
/**
* MarlinSerial_Due.cpp - Hardware serial library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
* Based on MarlinSerial for AVR, copyright (c) 2006 Nicholas Zambetti. All right reserved.
*/
#include "../../inc/MarlinConfig.h"
#if HAS_USB_SERIAL
#include "MarlinSerialUSB.h"
// Imports from Atmel USB Stack/CDC implementation
extern "C" {
bool usb_task_cdc_isenabled();
bool usb_task_cdc_dtr_active();
bool udi_cdc_is_rx_ready();
int udi_cdc_getc();
bool udi_cdc_is_tx_ready();
int udi_cdc_putc(int value);
}
// Pending character
static int pending_char = -1;
// Public Methods
void MarlinSerialUSB::begin(const long) {}
void MarlinSerialUSB::end() {}
int MarlinSerialUSB::peek() {
if (pending_char >= 0)
return pending_char;
// If USB CDC not enumerated or not configured on the PC side
if (!usb_task_cdc_isenabled())
return -1;
// If no bytes sent from the PC
if (!udi_cdc_is_rx_ready())
return -1;
pending_char = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT1*>(this)->emergency_state, (char)pending_char));
return pending_char;
}
int MarlinSerialUSB::read() {
if (pending_char >= 0) {
int ret = pending_char;
pending_char = -1;
return ret;
}
// If USB CDC not enumerated or not configured on the PC side
if (!usb_task_cdc_isenabled())
return -1;
// If no bytes sent from the PC
if (!udi_cdc_is_rx_ready())
return -1;
int c = udi_cdc_getc();
TERN_(EMERGENCY_PARSER, emergency_parser.update(static_cast<MSerialT1*>(this)->emergency_state, (char)c));
return c;
}
int MarlinSerialUSB::available() {
if (pending_char > 0) return pending_char;
return pending_char == 0 ||
// or USB CDC enumerated and configured on the PC side and some bytes where sent to us */
(usb_task_cdc_isenabled() && udi_cdc_is_rx_ready());
}
void MarlinSerialUSB::flush() { }
size_t MarlinSerialUSB::write(const uint8_t c) {
/* Do not even bother sending anything if USB CDC is not enumerated
or not configured on the PC side or there is no program on the PC
listening to our messages */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
return 0;
/* Wait until the PC has read the pending to be sent data */
while (usb_task_cdc_isenabled() &&
usb_task_cdc_dtr_active() &&
!udi_cdc_is_tx_ready()) {
};
/* Do not even bother sending anything if USB CDC is not enumerated
or not configured on the PC side or there is no program on the PC
listening to our messages at this point */
if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
return 0;
// Fifo full
// udi_cdc_signal_overrun();
udi_cdc_putc(c);
return 1;
}
// Preinstantiate
#if SERIAL_PORT == -1
MSerialT1 customizedSerial1(TERN0(EMERGENCY_PARSER, true));
#endif
#if SERIAL_PORT_2 == -1
MSerialT2 customizedSerial2(TERN0(EMERGENCY_PARSER, true));
#endif
#if SERIAL_PORT_3 == -1
MSerialT3 customizedSerial3(TERN0(EMERGENCY_PARSER, true));
#endif
#endif // HAS_USB_SERIAL
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,65 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* MarlinSerialUSB_Due.h - Hardware Serial over USB (CDC) library for Arduino DUE
* Copyright (c) 2017 Eduardo José Tagle. All right reserved
*/
#include "../../inc/MarlinConfig.h"
#include "../../core/serial_hook.h"
#include <WString.h>
struct MarlinSerialUSB {
void begin(const long);
void end();
int peek();
int read();
void flush();
int available();
size_t write(const uint8_t c);
#if ENABLED(SERIAL_STATS_DROPPED_RX)
FORCE_INLINE uint32_t dropped() { return 0; }
#endif
#if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
FORCE_INLINE int rxMaxEnqueued() { return 0; }
#endif
};
#if SERIAL_PORT == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT1;
extern MSerialT1 customizedSerial1;
#endif
#if SERIAL_PORT_2 == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT2;
extern MSerialT2 customizedSerial2;
#endif
#if SERIAL_PORT_3 == -1
typedef Serial1Class<MarlinSerialUSB> MSerialT3;
extern MSerialT3 customizedSerial3;
#endif

91
src/HAL/DUE/MinSerial.cpp Normal file
View File

@ -0,0 +1,91 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfigPre.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
#include "../shared/MinSerial.h"
#include <stdarg.h>
static void TXBegin() {
// Disable UART interrupt in NVIC
NVIC_DisableIRQ( UART_IRQn );
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable clock
pmc_disable_periph_clk( ID_UART );
// Configure PMC
pmc_enable_periph_clk( ID_UART );
// Disable PDC channel
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
// Reset and disable receiver and transmitter
UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
// Configure mode: 8bit, No parity, 1 bit stop
UART->UART_MR = UART_MR_CHMODE_NORMAL | US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO;
// Configure baudrate (asynchronous, no oversampling) to BAUDRATE bauds
UART->UART_BRGR = (SystemCoreClock / (BAUDRATE << 4));
// Enable receiver and transmitter
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
// A SW memory barrier, to ensure GCC does not overoptimize loops
#define sw_barrier() __asm__ volatile("": : :"memory");
static void TX(char c) {
while (!(UART->UART_SR & UART_SR_TXRDY)) { WDT_Restart(WDT); sw_barrier(); };
UART->UART_THR = c;
}
void install_min_serial() {
HAL_min_serial_init = &TXBegin;
HAL_min_serial_out = &TX;
}
#if DISABLED(DYNAMIC_VECTORTABLE)
extern "C" {
__attribute__((naked)) void JumpHandler_ASM() {
__asm__ __volatile__ (
"b CommonHandler_ASM\n"
);
}
void __attribute__((naked, alias("JumpHandler_ASM"))) HardFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) BusFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) UsageFault_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) MemManage_Handler();
void __attribute__((naked, alias("JumpHandler_ASM"))) NMI_Handler();
}
#endif
#endif // POSTMORTEM_DEBUGGING
#endif // ARDUINO_ARCH_SAM

163
src/HAL/DUE/Servo.cpp Normal file
View File

@ -0,0 +1,163 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/*
Copyright (c) 2013 Arduino LLC. 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
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#if HAS_SERVOS
#include "../shared/servo.h"
#include "../shared/servo_private.h"
static Flags<_Nbr_16timers> DisablePending; // ISR should disable the timer at the next timer reset
// ------------------------
/// Interrupt handler for the TC0 channel 1.
// ------------------------
void Servo_Handler(const timer16_Sequence_t, Tc*, const uint8_t);
#ifdef _useTimer1
void HANDLER_FOR_TIMER1() { Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1); }
#endif
#ifdef _useTimer2
void HANDLER_FOR_TIMER2() { Servo_Handler(_timer2, TC_FOR_TIMER2, CHANNEL_FOR_TIMER2); }
#endif
#ifdef _useTimer3
void HANDLER_FOR_TIMER3() { Servo_Handler(_timer3, TC_FOR_TIMER3, CHANNEL_FOR_TIMER3); }
#endif
#ifdef _useTimer4
void HANDLER_FOR_TIMER4() { Servo_Handler(_timer4, TC_FOR_TIMER4, CHANNEL_FOR_TIMER4); }
#endif
#ifdef _useTimer5
void HANDLER_FOR_TIMER5() { Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5); }
#endif
void Servo_Handler(const timer16_Sequence_t timer, Tc *tc, const uint8_t channel) {
static int8_t Channel[_Nbr_16timers]; // Servo counters to pulse (or -1 for refresh interval)
int8_t cho = Channel[timer]; // Handle the prior Channel[timer] first
if (cho < 0) { // Channel -1 indicates the refresh interval completed...
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // ...so reset the timer
if (DisablePending[timer]) {
// Disabling only after the full servo period expires prevents
// pulses being too close together if immediately re-enabled.
DisablePending.clear(timer);
TC_Stop(tc, channel);
tc->TC_CHANNEL[channel].TC_SR; // clear interrupt
return;
}
}
else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
Channel[timer] = ++cho; // go to the next channel (or 0)
if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer, cho).ticks;
if (SERVO(timer, cho).Pin.isActive) // activated?
extDigitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
}
else {
// finished all channels so wait for the refresh period to expire before starting over
const unsigned int cval = tc->TC_CHANNEL[channel].TC_CV + 128 / (SERVO_TIMER_PRESCALER), // allow 128 cycles to ensure the next CV not missed
ival = (unsigned int)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
tc->TC_CHANNEL[channel].TC_RA = max(cval, ival);
Channel[timer] = -1; // reset the timer CCR on the next call
}
tc->TC_CHANNEL[channel].TC_SR; // clear interrupt
}
static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn) {
pmc_enable_periph_clk(id);
TC_Configure(tc, channel,
TC_CMR_WAVE // Waveform mode
| TC_CMR_WAVSEL_UP_RC // Counter running up and reset when equal to RC
| (SERVO_TIMER_PRESCALER == 2 ? TC_CMR_TCCLKS_TIMER_CLOCK1 : 0) // MCK/2
| (SERVO_TIMER_PRESCALER == 8 ? TC_CMR_TCCLKS_TIMER_CLOCK2 : 0) // MCK/8
| (SERVO_TIMER_PRESCALER == 32 ? TC_CMR_TCCLKS_TIMER_CLOCK3 : 0) // MCK/32
| (SERVO_TIMER_PRESCALER == 128 ? TC_CMR_TCCLKS_TIMER_CLOCK4 : 0) // MCK/128
);
// Wait 1ms before the first ISR
TC_SetRA(tc, channel, (F_CPU) / (SERVO_TIMER_PRESCALER) / 1000UL); // 1ms
// Configure and enable interrupt
NVIC_EnableIRQ(irqn);
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS; // TC_IER_CPAS: RA Compare
// Enables the timer clock and performs a software reset to start the counting
TC_Start(tc, channel);
}
void initISR(const timer16_Sequence_t timer_index) {
CRITICAL_SECTION_START();
const bool disable_soon = DisablePending[timer_index];
DisablePending.clear(timer_index);
CRITICAL_SECTION_END();
if (!disable_soon) switch (timer_index) {
default: break;
#ifdef _useTimer1
case _timer1: return _initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
#endif
#ifdef _useTimer2
case _timer2: return _initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
#endif
#ifdef _useTimer3
case _timer3: return _initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
#endif
#ifdef _useTimer4
case _timer4: return _initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
#endif
#ifdef _useTimer5
case _timer5: return _initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
#endif
}
}
void finISR(const timer16_Sequence_t timer_index) {
// Timer is disabled from the ISR, to ensure proper final pulse length.
DisablePending.set(timer_index);
}
#endif // HAS_SERVOS
#endif // ARDUINO_ARCH_SAM

107
src/HAL/DUE/ServoTimers.h Normal file
View File

@ -0,0 +1,107 @@
/**
* Copyright (c) 2013 Arduino LLC. 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
*/
/**
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 32 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many timers are available.
*/
/**
* SAM Only definitions
* --------------------
*/
// For SAM3X:
//!#define _useTimer1
//!#define _useTimer2
#define _useTimer3
//!#define _useTimer4
#define _useTimer5
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
#define SERVO_TIMER_PRESCALER 2 // timer prescaler
/*
TC0, chan 0 => TC0_Handler
TC0, chan 1 => TC1_Handler
TC0, chan 2 => TC2_Handler
TC1, chan 0 => TC3_Handler
TC1, chan 1 => TC4_Handler
TC1, chan 2 => TC5_Handler
TC2, chan 0 => TC6_Handler
TC2, chan 1 => TC7_Handler
TC2, chan 2 => TC8_Handler
*/
#ifdef _useTimer1
#define TC_FOR_TIMER1 TC1
#define CHANNEL_FOR_TIMER1 0
#define ID_TC_FOR_TIMER1 ID_TC3
#define IRQn_FOR_TIMER1 TC3_IRQn
#define HANDLER_FOR_TIMER1 TC3_Handler
#endif
#ifdef _useTimer2
#define TC_FOR_TIMER2 TC1
#define CHANNEL_FOR_TIMER2 1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#endif
#ifdef _useTimer3
#define TC_FOR_TIMER3 TC1
#define CHANNEL_FOR_TIMER3 2
#define ID_TC_FOR_TIMER3 ID_TC5
#define IRQn_FOR_TIMER3 TC5_IRQn
#define HANDLER_FOR_TIMER3 TC5_Handler
#endif
#ifdef _useTimer4
#define TC_FOR_TIMER4 TC0
#define CHANNEL_FOR_TIMER4 2
#define ID_TC_FOR_TIMER4 ID_TC2
#define IRQn_FOR_TIMER4 TC2_IRQn
#define HANDLER_FOR_TIMER4 TC2_Handler
#endif
#ifdef _useTimer5
#define TC_FOR_TIMER5 TC0
#define CHANNEL_FOR_TIMER5 0
#define ID_TC_FOR_TIMER5 ID_TC0
#define IRQn_FOR_TIMER5 TC0_IRQn
#define HANDLER_FOR_TIMER5 TC0_Handler
#endif
typedef enum : unsigned char {
#ifdef _useTimer1
_timer1,
#endif
#ifdef _useTimer2
_timer2,
#endif
#ifdef _useTimer3
_timer3,
#endif
#ifdef _useTimer4
_timer4,
#endif
#ifdef _useTimer5
_timer5,
#endif
_Nbr_16timers
} timer16_Sequence_t;

60
src/HAL/DUE/Tone.cpp Normal file
View File

@ -0,0 +1,60 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Description: Tone function for Arduino Due and compatible (SAM3X8E)
* Derived from https://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
static pin_t tone_pin;
volatile static int32_t toggles;
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration/*=0*/) {
tone_pin = _pin;
toggles = 2 * frequency * duration / 1000;
HAL_timer_start(MF_TIMER_TONE, 2 * frequency);
}
void noTone(const pin_t _pin) {
HAL_timer_disable_interrupt(MF_TIMER_TONE);
extDigitalWrite(_pin, LOW);
}
HAL_TONE_TIMER_ISR() {
static uint8_t pin_state = 0;
HAL_timer_isr_prologue(MF_TIMER_TONE);
if (toggles) {
toggles--;
extDigitalWrite(tone_pin, (pin_state ^= 1));
}
else noTone(tone_pin); // turn off interrupt
}
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,143 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Based on u8g_com_msp430_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2012, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef __SAM3X8E__
#include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB
#include <U8glib-HAL.h>
#include "../../../MarlinCore.h"
#ifndef LCD_SPI_SPEED
#define LCD_SPI_SPEED SPI_QUARTER_SPEED
#endif
#include "../../shared/HAL_SPI.h"
#include "../fastio.h"
void u8g_SetPIOutput_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index) {
PIO_Configure(g_APinDescription[u8g->pin_list[pin_index]].pPort, PIO_OUTPUT_1,
g_APinDescription[u8g->pin_list[pin_index]].ulPin, g_APinDescription[u8g->pin_list[pin_index]].ulPinConfiguration); // OUTPUT
}
void u8g_SetPILevel_DUE_hw_spi(u8g_t *u8g, uint8_t pin_index, uint8_t level) {
volatile Pio* port = g_APinDescription[u8g->pin_list[pin_index]].pPort;
uint32_t mask = g_APinDescription[u8g->pin_list[pin_index]].ulPin;
if (level) port->PIO_SODR = mask;
else port->PIO_CODR = mask;
}
uint8_t u8g_com_HAL_DUE_shared_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_INIT:
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_CS, 1);
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_A0, 1);
u8g_SetPIOutput_DUE_hw_spi(u8g, U8G_PI_CS);
u8g_SetPIOutput_DUE_hw_spi(u8g, U8G_PI_A0);
u8g_Delay(5);
spiBegin();
spiInit(LCD_SPI_SPEED);
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_A0, arg_val);
break;
case U8G_COM_MSG_CHIP_SELECT:
u8g_SetPILevel_DUE_hw_spi(u8g, U8G_PI_CS, (arg_val ? 0 : 1));
break;
case U8G_COM_MSG_RESET:
break;
case U8G_COM_MSG_WRITE_BYTE:
spiSend((uint8_t)arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
spiSend(*ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
spiSend(*ptr++);
arg_val--;
}
}
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB
#endif // __SAM3X8E__

View File

@ -0,0 +1,186 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Based on u8g_com_st7920_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2011, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfigPre.h"
#if IS_U8GLIB_ST7920
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include <U8glib-HAL.h>
#include "u8g_com_HAL_DUE_sw_spi_shared.h"
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_0
static uint8_t rs_last_state = 255;
static void u8g_com_DUE_st7920_write_byte_sw_spi(uint8_t rs, uint8_t val) {
if (rs != rs_last_state) { // time to send a command/data byte
rs_last_state = rs;
SPISEND_SW_DUE(rs ? 0x0FA : 0x0F8); // Command or Data
DELAY_US(40); // give the controller some time to process the data: 20 is bad, 30 is OK, 40 is safe
}
SPISEND_SW_DUE(val & 0xF0);
SPISEND_SW_DUE(val << 4);
}
uint8_t u8g_com_HAL_DUE_ST7920_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
SCK_pPio = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].pPort;
SCK_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].ulPin;
MOSI_pPio = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].pPort;
MOSI_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].ulPin;
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, 0);
u8g_SetPIOutput_DUE(u8g, U8G_PI_CS);
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 0);
u8g_SetPIOutput_DUE(u8g, U8G_PI_SCK);
u8g_SetPILevel_DUE(u8g, U8G_PI_MOSI, 0);
u8g_SetPIOutput_DUE(u8g, U8G_PI_MOSI);
SCK_pPio->PIO_CODR = SCK_dwMask; //SCK low - needed at power up but not after reset
MOSI_pPio->PIO_CODR = MOSI_dwMask; //MOSI low - needed at power up but not after reset
u8g_Delay(5);
u8g->pin_list[U8G_PI_A0_STATE] = 0; /* initial RS state: command mode */
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel_DUE(u8g, U8G_PI_RESET, arg_val);
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g->pin_list[U8G_PI_A0_STATE] = arg_val;
break;
case U8G_COM_MSG_CHIP_SELECT:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_CS])
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, arg_val); //note: the st7920 has an active high chip select
break;
case U8G_COM_MSG_WRITE_BYTE:
u8g_com_DUE_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
u8g_com_DUE_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t*) arg_ptr;
while (arg_val > 0) {
u8g_com_DUE_st7920_write_byte_sw_spi(u8g->pin_list[U8G_PI_A0_STATE], *ptr++);
arg_val--;
}
}
break;
}
return 1;
}
#if ENABLED(LIGHTWEIGHT_UI)
#include "../../../lcd/marlinui.h"
#include "../../shared/HAL_ST7920.h"
#define ST7920_CS_PIN LCD_PINS_RS
#if DOGM_SPI_DELAY_US > 0
#define U8G_DELAY() DELAY_US(DOGM_SPI_DELAY_US)
#else
#define U8G_DELAY() DELAY_US(10)
#endif
void ST7920_cs() {
WRITE(ST7920_CS_PIN, HIGH);
U8G_DELAY();
}
void ST7920_ncs() {
WRITE(ST7920_CS_PIN, LOW);
}
void ST7920_set_cmd() {
SPISEND_SW_DUE(0xF8);
DELAY_US(40);
}
void ST7920_set_dat() {
SPISEND_SW_DUE(0xFA);
DELAY_US(40);
}
void ST7920_write_byte(const uint8_t val) {
SPISEND_SW_DUE(val & 0xF0);
SPISEND_SW_DUE(val << 4);
}
#endif // LIGHTWEIGHT_UI
#endif // IS_U8GLIB_ST7920
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,145 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Based on u8g_com_std_sw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2015, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920
#include "u8g_com_HAL_DUE_sw_spi_shared.h"
#include "../../shared/Marduino.h"
#include "../../shared/Delay.h"
#include <U8glib-HAL.h>
#if ENABLED(FYSETC_MINI_12864)
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_3
#else
#define SPISEND_SW_DUE u8g_spiSend_sw_DUE_mode_0
#endif
uint8_t u8g_com_HAL_DUE_sw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr) {
switch (msg) {
case U8G_COM_MSG_INIT:
SCK_pPio = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].pPort;
SCK_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_SCK]].ulPin;
MOSI_pPio = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].pPort;
MOSI_dwMask = g_APinDescription[u8g->pin_list[U8G_PI_MOSI]].ulPin;
u8g_SetPIOutput_DUE(u8g, U8G_PI_SCK);
u8g_SetPIOutput_DUE(u8g, U8G_PI_MOSI);
u8g_SetPIOutput_DUE(u8g, U8G_PI_CS);
u8g_SetPIOutput_DUE(u8g, U8G_PI_A0);
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPIOutput_DUE(u8g, U8G_PI_RESET);
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 0);
u8g_SetPILevel_DUE(u8g, U8G_PI_MOSI, 0);
break;
case U8G_COM_MSG_STOP:
break;
case U8G_COM_MSG_RESET:
if (U8G_PIN_NONE != u8g->pin_list[U8G_PI_RESET]) u8g_SetPILevel_DUE(u8g, U8G_PI_RESET, arg_val);
break;
case U8G_COM_MSG_CHIP_SELECT:
#if ENABLED(FYSETC_MINI_12864) // LCD SPI is running mode 3 while SD card is running mode 0
if (arg_val) { // SCK idle state needs to be set to the proper idle state before
// the next chip select goes active
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 1); //set SCK to mode 3 idle state before CS goes active
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, LOW);
}
else {
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, HIGH);
u8g_SetPILevel_DUE(u8g, U8G_PI_SCK, 0); //set SCK to mode 0 idle state after CS goes inactive
}
#else
u8g_SetPILevel_DUE(u8g, U8G_PI_CS, !arg_val);
#endif
break;
case U8G_COM_MSG_WRITE_BYTE:
SPISEND_SW_DUE(arg_val);
break;
case U8G_COM_MSG_WRITE_SEQ: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_DUE(*ptr++);
arg_val--;
}
}
break;
case U8G_COM_MSG_WRITE_SEQ_P: {
uint8_t *ptr = (uint8_t *)arg_ptr;
while (arg_val > 0) {
SPISEND_SW_DUE(u8g_pgm_read(ptr));
ptr++;
arg_val--;
}
}
break;
case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
u8g_SetPILevel_DUE(u8g, U8G_PI_A0, arg_val);
break;
}
return 1;
}
#endif // HAS_MARLINUI_U8GLIB && !IS_U8GLIB_ST7920
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,113 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Based on u8g_com_st7920_hw_spi.c
*
* Universal 8bit Graphics Library
*
* Copyright (c) 2011, olikraus@gmail.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfigPre.h"
#if HAS_MARLINUI_U8GLIB
#include "../../../inc/MarlinConfig.h"
#include "../../shared/Delay.h"
#include <U8glib-HAL.h>
#include "u8g_com_HAL_DUE_sw_spi_shared.h"
void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index) {
PIO_Configure(g_APinDescription[u8g->pin_list[pin_index]].pPort, PIO_OUTPUT_1,
g_APinDescription[u8g->pin_list[pin_index]].ulPin, g_APinDescription[u8g->pin_list[pin_index]].ulPinConfiguration); // OUTPUT
}
void u8g_SetPILevel_DUE(u8g_t *u8g, uint8_t pin_index, uint8_t level) {
volatile Pio* port = g_APinDescription[u8g->pin_list[pin_index]].pPort;
uint32_t mask = g_APinDescription[u8g->pin_list[pin_index]].ulPin;
if (level) port->PIO_SODR = mask; else port->PIO_CODR = mask;
}
Pio *SCK_pPio, *MOSI_pPio;
uint32_t SCK_dwMask, MOSI_dwMask;
void u8g_spiSend_sw_DUE_mode_0(uint8_t val) { // 3MHz
LOOP_L_N(i, 8) {
if (val & 0x80)
MOSI_pPio->PIO_SODR = MOSI_dwMask;
else
MOSI_pPio->PIO_CODR = MOSI_dwMask;
DELAY_NS(48);
SCK_pPio->PIO_SODR = SCK_dwMask;
DELAY_NS(905);
val <<= 1;
SCK_pPio->PIO_CODR = SCK_dwMask;
}
}
void u8g_spiSend_sw_DUE_mode_3(uint8_t val) { // 3.5MHz
LOOP_L_N(i, 8) {
SCK_pPio->PIO_CODR = SCK_dwMask;
DELAY_NS(50);
if (val & 0x80)
MOSI_pPio->PIO_SODR = MOSI_dwMask;
else
MOSI_pPio->PIO_CODR = MOSI_dwMask;
val <<= 1;
DELAY_NS(10);
SCK_pPio->PIO_SODR = SCK_dwMask;
DELAY_NS(70);
}
}
#endif // HAS_MARLINUI_U8GLIB
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,35 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../../../inc/MarlinConfigPre.h"
#include "../../shared/Marduino.h"
#include <U8glib-HAL.h>
void u8g_SetPIOutput_DUE(u8g_t *u8g, uint8_t pin_index);
void u8g_SetPILevel_DUE(u8g_t *u8g, uint8_t pin_index, uint8_t level);
void u8g_spiSend_sw_DUE_mode_0(uint8_t val);
void u8g_spiSend_sw_DUE_mode_3(uint8_t val);
extern Pio *SCK_pPio, *MOSI_pPio;
extern uint32_t SCK_dwMask, MOSI_dwMask;

View File

@ -0,0 +1,998 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#if ENABLED(FLASH_EEPROM_EMULATION)
/* EEPROM emulation over flash with reduced wear
*
* We will use 2 contiguous groups of pages as main and alternate.
* We want an structure that allows to read as fast as possible,
* without the need of scanning the whole FLASH memory.
*
* FLASH bits default erased state is 1, and can be set to 0
* on a per bit basis. To reset them to 1, a full page erase
* is needed.
*
* Values are stored as differences that should be applied to a
* completely erased EEPROM (filled with 0xFFs). We just encode
* the starting address of the values to change, the length of
* the block of new values, and the values themselves. All diffs
* are accumulated into a RAM buffer, compacted into the least
* amount of non overlapping diffs possible and sorted by starting
* address before being saved into the next available page of FLASH
* of the current group.
* Once the current group is completely full, we compact it and save
* it into the other group, then erase the current group and switch
* to that new group and set it as current.
*
* The FLASH endurance is about 1/10 ... 1/100 of an EEPROM
* endurance, but EEPROM endurance is specified per byte, not
* per page. We can't emulate EE endurance with FLASH for all
* bytes, but we can emulate endurance for a given percent of
* bytes.
*/
//#define EE_EMU_DEBUG
#define EEPROMSize 4096
#define PagesPerGroup 128
#define GroupCount 2
#define PageSize 256U
/* Flash storage */
typedef struct FLASH_SECTOR {
uint8_t page[PageSize];
} FLASH_SECTOR_T;
#define PAGE_FILL \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, \
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
#define FLASH_INIT_FILL \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL, \
PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL,PAGE_FILL
/* This is the FLASH area used to emulate a 2Kbyte EEPROM -- We need this buffer aligned
to a 256 byte boundary. */
static const uint8_t flashStorage[PagesPerGroup * GroupCount * PageSize] __attribute__ ((aligned (PageSize))) = { FLASH_INIT_FILL };
/* Get the address of an specific page */
static const FLASH_SECTOR_T* getFlashStorage(int page) {
return (const FLASH_SECTOR_T*)&flashStorage[page*PageSize];
}
static uint8_t buffer[256] = {0}, // The RAM buffer to accumulate writes
curPage = 0, // Current FLASH page inside the group
curGroup = 0xFF; // Current FLASH group
#define DEBUG_OUT ENABLED(EE_EMU_DEBUG)
#include "../../core/debug_out.h"
static void ee_Dump(const int page, const void *data) {
#ifdef EE_EMU_DEBUG
const uint8_t *c = (const uint8_t*) data;
char buffer[80];
sprintf_P(buffer, PSTR("Page: %d (0x%04x)\n"), page, page);
DEBUG_ECHO(buffer);
char* p = &buffer[0];
for (int i = 0; i< PageSize; ++i) {
if ((i & 0xF) == 0) p += sprintf_P(p, PSTR("%04x] "), i);
p += sprintf_P(p, PSTR(" %02x"), c[i]);
if ((i & 0xF) == 0xF) {
*p++ = '\n';
*p = 0;
DEBUG_ECHO(buffer);
p = &buffer[0];
}
}
#else
UNUSED(page);
UNUSED(data);
#endif
}
/* Flash Writing Protection Key */
#define FWP_KEY 0x5Au
#if SAM4S_SERIES
#define EEFC_FCR_FCMD(value) \
((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)
#else
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)
#endif
/**
* Writes the contents of the specified page (no previous erase)
* @param page (page #)
* @param data (pointer to the data buffer)
*/
__attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageWrite(uint16_t page, const void *data) {
uint16_t i;
uint32_t addrflash = uint32_t(getFlashStorage(page));
// Read the flash contents
uint32_t pageContents[PageSize>>2];
memcpy(pageContents, (void*)addrflash, PageSize);
// We ONLY want to toggle bits that have changed, and that have changed to 0.
// SAM3X8E tends to destroy contiguous bits if reprogrammed without erasing, so
// we try by all means to avoid this. That is why it says: "The Partial
// Programming mode works only with 128-bit (or higher) boundaries. It cannot
// be used with boundaries lower than 128 bits (8, 16 or 32-bit for example)."
// All bits that did not change, set them to 1.
for (i = 0; i <PageSize >> 2; i++)
pageContents[i] = (((uint32_t*)data)[i]) | (~(pageContents[i] ^ ((uint32_t*)data)[i]));
DEBUG_ECHO_MSG("EEPROM PageWrite ", page);
DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_FLUSH();
// Get the page relative to the start of the EFC controller, and the EFC controller to use
Efc *efc;
uint16_t fpage;
if (addrflash >= IFLASH1_ADDR) {
efc = EFC1;
fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
}
else {
efc = EFC0;
fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
}
// Get the page that must be unlocked, then locked
uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
// Disable all interrupts
__disable_irq();
// Get the FLASH wait states
uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
// Set wait states to 6 (SAM errata)
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
// Unlock the flash page
uint32_t status;
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Unlock failure for page ", page);
return false;
}
// Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
const uint32_t * aligned_src = (const uint32_t *) &pageContents[0]; /*data;*/
uint32_t * p_aligned_dest = (uint32_t *) addrflash;
for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
*p_aligned_dest++ = *aligned_src++;
}
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_WPL);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Write failure for page ", page);
return false;
}
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
// Compare contents
if (memcmp(getFlashStorage(page),data,PageSize)) {
#ifdef EE_EMU_DEBUG
DEBUG_ECHO_MSG("EEPROM Verify Write failure for page ", page);
ee_Dump( page, (uint32_t *)addrflash);
ee_Dump(-page, data);
// Calculate count of changed bits
uint32_t *p1 = (uint32_t*)addrflash;
uint32_t *p2 = (uint32_t*)data;
int count = 0;
for (i =0; i<PageSize >> 2; i++) {
if (p1[i] != p2[i]) {
uint32_t delta = p1[i] ^ p2[i];
while (delta) {
if ((delta&1) != 0)
count++;
delta >>= 1;
}
}
}
DEBUG_ECHOLNPGM("--> Differing bits: ", count);
#endif
return false;
}
return true;
}
/**
* Erases the contents of the specified page
* @param page (page #)
*/
__attribute__ ((long_call, section (".ramfunc")))
static bool ee_PageErase(uint16_t page) {
uint16_t i;
uint32_t addrflash = uint32_t(getFlashStorage(page));
DEBUG_ECHO_MSG("EEPROM PageErase ", page);
DEBUG_ECHOLNPGM(" in FLASH address ", (uint32_t)addrflash);
DEBUG_ECHOLNPGM(" base address ", (uint32_t)getFlashStorage(0));
DEBUG_FLUSH();
// Get the page relative to the start of the EFC controller, and the EFC controller to use
Efc *efc;
uint16_t fpage;
if (addrflash >= IFLASH1_ADDR) {
efc = EFC1;
fpage = (addrflash - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE;
}
else {
efc = EFC0;
fpage = (addrflash - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE;
}
// Get the page that must be unlocked, then locked
uint16_t lpage = fpage & (~((IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) - 1));
// Disable all interrupts
__disable_irq();
// Get the FLASH wait states
uint32_t orgWS = (efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos;
// Set wait states to 6 (SAM errata)
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(6);
// Unlock the flash page
uint32_t status;
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(lpage) | EEFC_FCR_FCMD(EFC_FCMD_CLB);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Unlock failure for page ",page);
return false;
}
// Erase Write page and lock: Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.
uint32_t * p_aligned_dest = (uint32_t *) addrflash;
for (i = 0; i < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++i) {
*p_aligned_dest++ = 0xFFFFFFFF;
}
efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(fpage) | EEFC_FCR_FCMD(EFC_FCMD_EWPL);
while (((status = efc->EEFC_FSR) & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
// force compiler to not optimize this -- NOPs don't work!
__asm__ __volatile__("");
};
if ((status & EEFC_ERROR_FLAGS) != 0) {
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
DEBUG_ECHO_MSG("EEPROM Erase failure for page ",page);
return false;
}
// Restore original wait states
efc->EEFC_FMR = (efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(orgWS);
// Reenable interrupts
__enable_irq();
// Check erase
uint32_t * aligned_src = (uint32_t *) addrflash;
for (i = 0; i < PageSize >> 2; i++) {
if (*aligned_src++ != 0xFFFFFFFF) {
DEBUG_ECHO_MSG("EEPROM Verify Erase failure for page ",page);
ee_Dump(page, (uint32_t *)addrflash);
return false;
}
}
return true;
}
static uint8_t ee_Read(uint32_t address, bool excludeRAMBuffer=false) {
uint32_t baddr;
uint32_t blen;
// If we were requested an address outside of the emulated range, fail now
if (address >= EEPROMSize)
return false;
// Check that the value is not contained in the RAM buffer
if (!excludeRAMBuffer) {
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
// Check if data is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Return it!
return buffer[i + 3 + address - baddr];
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address)
break;
// Jump to the next block
i += 3 + blen;
}
}
// It is NOT on the RAM buffer. It could be stored in FLASH. We are
// ensured on a given FLASH page, address contents are never repeated
// but on different pages, there is no such warranty, so we must go
// backwards from the last written FLASH page to the first one.
for (int page = curPage - 1; page >= 0; --page) {
// Get a pointer to the flash page
uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = pflash[i] | (pflash[i + 1] << 8);
// Get the length of the block
blen = pflash[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
// Check if data is contained in this block
if (address >= baddr && address < (baddr + blen))
return pflash[i + 3 + address - baddr]; // Yes, it is contained. Return it!
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
}
// If reached here, value is not stored, so return its default value
return 0xFF;
}
static uint32_t ee_GetAddrRange(uint32_t address, bool excludeRAMBuffer=false) {
uint32_t baddr,
blen,
nextAddr = 0xFFFF,
nextRange = 0;
// Check that the value is not contained in the RAM buffer
if (!excludeRAMBuffer) {
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF) break;
// Check if address and address + 1 is contained in this block
if (address >= baddr && address < (baddr + blen))
return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
// Otherwise, check if we can use it as a limit
if (baddr > address && baddr < nextAddr) {
nextAddr = baddr;
nextRange = blen;
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
}
// It is NOT on the RAM buffer. It could be stored in FLASH. We are
// ensured on a given FLASH page, address contents are never repeated
// but on different pages, there is no such warranty, so we must go
// backwards from the last written FLASH page to the first one.
for (int page = curPage - 1; page >= 0; --page) {
// Get a pointer to the flash page
uint8_t *pflash = (uint8_t*)getFlashStorage(page + curGroup * PagesPerGroup);
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
baddr = pflash[i] | (pflash[i + 1] << 8);
// Get the length of the block
blen = pflash[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF) break;
// Check if data is contained in this block
if (address >= baddr && address < (baddr + blen))
return address | ((blen - address + baddr) << 16); // Yes, it is contained. Return it!
// Otherwise, check if we can use it as a limit
if (baddr > address && baddr < nextAddr) {
nextAddr = baddr;
nextRange = blen;
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
}
// If reached here, we will return the next valid address
return nextAddr | (nextRange << 16);
}
static bool ee_IsPageClean(int page) {
uint32_t *pflash = (uint32_t*) getFlashStorage(page);
for (uint16_t i = 0; i < (PageSize >> 2); ++i)
if (*pflash++ != 0xFFFFFFFF) return false;
return true;
}
static bool ee_Flush(uint32_t overrideAddress = 0xFFFFFFFF, uint8_t overrideData=0xFF) {
// Check if RAM buffer has something to be written
bool isEmpty = true;
uint32_t *p = (uint32_t*) &buffer[0];
for (uint16_t j = 0; j < (PageSize >> 2); j++) {
if (*p++ != 0xFFFFFFFF) {
isEmpty = false;
break;
}
}
// If something has to be written, do so!
if (!isEmpty) {
// Write the current ram buffer into FLASH
ee_PageWrite(curPage + curGroup * PagesPerGroup, buffer);
// Clear the RAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Increment the page to use the next time
++curPage;
}
// Did we reach the maximum count of available pages per group for storage ?
if (curPage < PagesPerGroup) {
// Do we have an override address ?
if (overrideAddress < EEPROMSize) {
// Yes, just store the value into the RAM buffer
buffer[0] = overrideAddress & 0xFF;
buffer[0 + 1] = (overrideAddress >> 8) & 0xFF;
buffer[0 + 2] = 1;
buffer[0 + 3] = overrideData;
}
// Done!
return true;
}
// We have no space left on the current group - We must compact the values
uint16_t i = 0;
// Compute the next group to use
int curwPage = 0, curwGroup = curGroup + 1;
if (curwGroup >= GroupCount) curwGroup = 0;
uint32_t rdAddr = 0;
do {
// Get the next valid range
uint32_t addrRange = ee_GetAddrRange(rdAddr, true);
// Make sure not to skip the override address, if specified
int rdRange;
if (overrideAddress < EEPROMSize &&
rdAddr <= overrideAddress &&
(addrRange & 0xFFFF) > overrideAddress) {
rdAddr = overrideAddress;
rdRange = 1;
}
else {
rdAddr = addrRange & 0xFFFF;
rdRange = addrRange >> 16;
}
// If no range, break loop
if (rdRange == 0)
break;
do {
// Get the value
uint8_t rdValue = overrideAddress == rdAddr ? overrideData : ee_Read(rdAddr, true);
// Do not bother storing default values
if (rdValue != 0xFF) {
// If we have room, add it to the buffer
if (buffer[i + 2] == 0xFF) {
// Uninitialized buffer, just add it!
buffer[i] = rdAddr & 0xFF;
buffer[i + 1] = (rdAddr >> 8) & 0xFF;
buffer[i + 2] = 1;
buffer[i + 3] = rdValue;
}
else {
// Buffer already has contents. Check if we can extend it
// Get the address of the block
uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
uint32_t blen = buffer[i + 2];
// Can we expand it ?
if (rdAddr == (baddr + blen) &&
i < (PageSize - 4) && /* This block has a chance to contain data AND */
buffer[i + 2] < (PageSize - i - 3)) {/* There is room for this block to be expanded */
// Yes, do it
++buffer[i + 2];
// And store the value
buffer[i + 3 + rdAddr - baddr] = rdValue;
}
else {
// No, we can't expand it - Skip the existing block
i += 3 + blen;
// Can we create a new slot ?
if (i > (PageSize - 4)) {
// Not enough space - Write the current buffer to FLASH
ee_PageWrite(curwPage + curwGroup * PagesPerGroup, buffer);
// Advance write page (as we are compacting, should never overflow!)
++curwPage;
// Clear RAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Start fresh */
i = 0;
}
// Enough space, add the new block
buffer[i] = rdAddr & 0xFF;
buffer[i + 1] = (rdAddr >> 8) & 0xFF;
buffer[i + 2] = 1;
buffer[i + 3] = rdValue;
}
}
}
// Go to the next address
++rdAddr;
// Repeat for bytes of this range
} while (--rdRange);
// Repeat until we run out of ranges
} while (rdAddr < EEPROMSize);
// We must erase the previous group, in preparation for the next swap
for (int page = 0; page < curPage; page++) {
ee_PageErase(page + curGroup * PagesPerGroup);
}
// Finally, Now the active group is the created new group
curGroup = curwGroup;
curPage = curwPage;
// Done!
return true;
}
static bool ee_Write(uint32_t address, uint8_t data) {
// If we were requested an address outside of the emulated range, fail now
if (address >= EEPROMSize) return false;
// Lets check if we have a block with that data previously defined. Block
// start addresses are always sorted in ascending order
uint16_t i = 0;
while (i <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Get the address of the block
uint32_t baddr = buffer[i] | (buffer[i + 1] << 8);
// Get the length of the block
uint32_t blen = buffer[i + 2];
// If we reach the end of the list, break loop
if (blen == 0xFF)
break;
// Check if data is contained in this block
if (address >= baddr &&
address < (baddr + blen)) {
// Yes, it is contained. Just modify it
buffer[i + 3 + address - baddr] = data;
// Done!
return true;
}
// Maybe we could add it to the front or to the back
// of this block ?
if ((address + 1) == baddr || address == (baddr + blen)) {
// Potentially, it could be done. But we must ensure there is room
// so we can expand the block. Lets find how much free space remains
uint32_t iend = i;
do {
uint32_t ln = buffer[iend + 2];
if (ln == 0xFF) break;
iend += 3 + ln;
} while (iend <= (PageSize - 4)); /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
// Here, inxt points to the first free address in the buffer. Do we have room ?
if (iend < PageSize) {
// Yes, at least a byte is free - We can expand the block
// Do we have to insert at the beginning ?
if ((address + 1) == baddr) {
// Insert at the beginning
// Make room at the beginning for our byte
memmove(&buffer[i + 3 + 1], &buffer[i + 3], iend - i - 3);
// Adjust the header and store the data
buffer[i] = address & 0xFF;
buffer[i + 1] = (address >> 8) & 0xFF;
buffer[i + 2]++;
buffer[i + 3] = data;
}
else {
// Insert at the end - There is a very interesting thing that could happen here:
// Maybe we could coalesce the next block with this block. Let's try to do it!
uint16_t inext = i + 3 + blen;
if (inext <= (PageSize - 4) &&
(buffer[inext] | uint16_t(buffer[inext + 1] << 8)) == (baddr + blen + 1)) {
// YES! ... we can coalesce blocks! . Do it!
// Adjust this block header to include the next one
buffer[i + 2] += buffer[inext + 2] + 1;
// Store data at the right place
buffer[i + 3 + blen] = data;
// Remove the next block header and append its data
memmove(&buffer[inext + 1], &buffer[inext + 3], iend - inext - 3);
// Finally, as we have saved 2 bytes at the end, make sure to clean them
buffer[iend - 2] = 0xFF;
buffer[iend - 1] = 0xFF;
}
else {
// NO ... No coalescing possible yet
// Make room at the end for our byte
memmove(&buffer[i + 3 + blen + 1], &buffer[i + 3 + blen], iend - i - 3 - blen);
// And add the data to the block
buffer[i + 2]++;
buffer[i + 3 + blen] = data;
}
}
// Done!
return true;
}
}
// As blocks are always sorted, if the starting address of this block is higher
// than the address we are looking for, break loop now - We wont find the value
// associated to the address
if (baddr > address) break;
// Jump to the next block
i += 3 + blen;
}
// Value is not stored AND we can't expand previous block to contain it. We must create a new block
// First, lets find how much free space remains
uint32_t iend = i;
while (iend <= (PageSize - 4)) { /* (PageSize - 4) because otherwise, there is not enough room for data and headers */
uint32_t ln = buffer[iend + 2];
if (ln == 0xFF) break;
iend += 3 + ln;
}
// If there is room for a new block, insert it at the proper place
if (iend <= (PageSize - 4)) {
// We have room to create a new block. Do so --- But add
// the block at the proper position, sorted by starting
// address, so it will be possible to compact it with other blocks.
// Make space
memmove(&buffer[i + 4], &buffer[i], iend - i);
// And add the block
buffer[i] = address & 0xFF;
buffer[i + 1] = (address >> 8) & 0xFF;
buffer[i + 2] = 1;
buffer[i + 3] = data;
// Done!
return true;
}
// Not enough room to store this information on this FLASH page - Perform a
// flush and override the address with the specified contents
return ee_Flush(address, data);
}
static void ee_Init() {
// Just init once!
if (curGroup != 0xFF) return;
// Clean up the SRAM buffer
memset(buffer, 0xFF, sizeof(buffer));
// Now, we must find out the group where settings are stored
for (curGroup = 0; curGroup < GroupCount; curGroup++)
if (!ee_IsPageClean(curGroup * PagesPerGroup)) break;
// If all groups seem to be used, default to first group
if (curGroup >= GroupCount) curGroup = 0;
DEBUG_ECHO_MSG("EEPROM Current Group: ",curGroup);
DEBUG_FLUSH();
// Now, validate that all the other group pages are empty
for (int grp = 0; grp < GroupCount; grp++) {
if (grp == curGroup) continue;
for (int page = 0; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(grp * PagesPerGroup + page)) {
DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on group ", grp);
DEBUG_FLUSH();
ee_PageErase(grp * PagesPerGroup + page);
}
}
}
// Finally, for the active group, determine the first unused page
// and also validate that all the other ones are clean
for (curPage = 0; curPage < PagesPerGroup; curPage++) {
if (ee_IsPageClean(curGroup * PagesPerGroup + curPage)) {
ee_Dump(curGroup * PagesPerGroup + curPage, getFlashStorage(curGroup * PagesPerGroup + curPage));
break;
}
}
DEBUG_ECHO_MSG("EEPROM Active page: ", curPage);
DEBUG_FLUSH();
// Make sure the pages following the first clean one are also clean
for (int page = curPage + 1; page < PagesPerGroup; page++) {
if (!ee_IsPageClean(curGroup * PagesPerGroup + page)) {
DEBUG_ECHO_MSG("EEPROM Page ", page, " not clean on active group ", curGroup);
DEBUG_FLUSH();
ee_Dump(curGroup * PagesPerGroup + page, getFlashStorage(curGroup * PagesPerGroup + page));
ee_PageErase(curGroup * PagesPerGroup + page);
}
}
}
/* PersistentStore -----------------------------------------------------------*/
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#define MARLIN_EEPROM_SIZE 0x1000 // 4KB
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { ee_Init(); return true; }
bool PersistentStore::access_finish() { ee_Flush(); return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
if (v != ee_Read(uint32_t(p))) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
ee_Write(uint32_t(p), v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (ee_Read(uint32_t(p)) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = ee_Read(uint32_t(pos));
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
#endif // FLASH_EEPROM_EMULATION
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,76 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
* Copyright (c) 2016 Victor Perez victor_pv@hotmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../inc/MarlinConfig.h"
#if USE_WIRED_EEPROM
/**
* PersistentStore for Arduino-style EEPROM interface
* with simple implementations supplied by Marlin.
*/
#include "../shared/eeprom_if.h"
#include "../shared/eeprom_api.h"
#ifndef MARLIN_EEPROM_SIZE
#error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM."
#endif
size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
bool PersistentStore::access_start() { eeprom_init(); return true; }
bool PersistentStore::access_finish() { return true; }
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
uint16_t written = 0;
while (size--) {
uint8_t * const p = (uint8_t * const)pos;
uint8_t v = *value;
if (v != eeprom_read_byte(p)) { // EEPROM has only ~100,000 write cycles, so only write bytes that have changed!
eeprom_write_byte(p, v);
if (++written & 0x7F) delay(2); else safe_delay(2); // Avoid triggering watchdog during long EEPROM writes
if (eeprom_read_byte(p) != v) {
SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
return true;
}
}
crc16(crc, &v, 1);
pos++;
value++;
}
return false;
}
bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
do {
uint8_t c = eeprom_read_byte((uint8_t*)pos);
if (writing) *value = c;
crc16(crc, &c, 1);
pos++;
value++;
} while (--size);
return false;
}
#endif // USE_WIRED_EEPROM
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,73 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Endstop Interrupts
*
* Without endstop interrupts the endstop pins must be polled continually in
* the temperature-ISR via endstops.update(), most of the time finding no change.
* With this feature endstops.update() is called only when we know that at
* least one endstop has changed state, saving valuable CPU cycles.
*
* This feature only works when all used endstop pins can generate an 'external interrupt'.
*
* Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'.
* (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino)
*/
#include "../../module/endstops.h"
// One ISR for all EXT-Interrupts
void endstop_ISR() { endstops.update(); }
/**
* Endstop interrupts for Due based targets.
* On Due, all pins support external interrupt capability.
*/
void setup_endstop_interrupts() {
#define _ATTACH(P) attachInterrupt(digitalPinToInterrupt(P), endstop_ISR, CHANGE)
TERN_(HAS_X_MAX, _ATTACH(X_MAX_PIN));
TERN_(HAS_X_MIN, _ATTACH(X_MIN_PIN));
TERN_(HAS_Y_MAX, _ATTACH(Y_MAX_PIN));
TERN_(HAS_Y_MIN, _ATTACH(Y_MIN_PIN));
TERN_(HAS_Z_MAX, _ATTACH(Z_MAX_PIN));
TERN_(HAS_Z_MIN, _ATTACH(Z_MIN_PIN));
TERN_(HAS_X2_MAX, _ATTACH(X2_MAX_PIN));
TERN_(HAS_X2_MIN, _ATTACH(X2_MIN_PIN));
TERN_(HAS_Y2_MAX, _ATTACH(Y2_MAX_PIN));
TERN_(HAS_Y2_MIN, _ATTACH(Y2_MIN_PIN));
TERN_(HAS_Z2_MAX, _ATTACH(Z2_MAX_PIN));
TERN_(HAS_Z2_MIN, _ATTACH(Z2_MIN_PIN));
TERN_(HAS_Z3_MAX, _ATTACH(Z3_MAX_PIN));
TERN_(HAS_Z3_MIN, _ATTACH(Z3_MIN_PIN));
TERN_(HAS_Z4_MAX, _ATTACH(Z4_MAX_PIN));
TERN_(HAS_Z4_MIN, _ATTACH(Z4_MIN_PIN));
TERN_(HAS_Z_MIN_PROBE_PIN, _ATTACH(Z_MIN_PROBE_PIN));
TERN_(HAS_I_MAX, _ATTACH(I_MAX_PIN));
TERN_(HAS_I_MIN, _ATTACH(I_MIN_PIN));
TERN_(HAS_J_MAX, _ATTACH(J_MAX_PIN));
TERN_(HAS_J_MIN, _ATTACH(J_MIN_PIN));
TERN_(HAS_K_MAX, _ATTACH(K_MAX_PIN));
TERN_(HAS_K_MIN, _ATTACH(K_MIN_PIN));
}

565
src/HAL/DUE/fastio.h Normal file
View File

@ -0,0 +1,565 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Fast I/O Routines for SAM3X8E
* Use direct port manipulation to save scads of processor time.
* Contributed by Triffid_Hunter and modified by Kliment, thinkyhead, Bob-the-Kuhn, et.al.
*/
/**
* Description: Fast IO functions for Arduino Due and compatible (SAM3X8E)
*
* For ARDUINO_ARCH_SAM
* Note the code here was specifically crafted by disassembling what GCC produces
* out of it, so GCC is able to optimize it out as much as possible to the least
* amount of instructions. Be very careful if you modify them, as "clean code"
* leads to less efficient compiled code!!
*/
#include <pins_arduino.h>
#include "../../inc/MarlinConfigPre.h"
/**
* Utility functions
*/
// Due has 12 PWMs assigned to logical pins 2-13.
// 6, 7, 8 & 9 come from the PWM controller. The others come from the timers.
#define PWM_PIN(P) WITHIN(P, 2, 13)
#ifndef MASK
#define MASK(PIN) _BV(PIN)
#endif
/**
* Magic I/O routines
*
* Now you can simply SET_OUTPUT(STEP); WRITE(STEP, HIGH); WRITE(STEP, LOW);
*
* Why double up on these macros? see https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
*/
// Read a pin
#define _READ(IO) bool(DIO ## IO ## _WPORT -> PIO_PDSR & MASK(DIO ## IO ## _PIN))
// Write to a pin
#define _WRITE(IO,V) do { \
volatile Pio* port = (DIO ## IO ## _WPORT); \
const uint32_t mask = MASK(DIO ## IO ## _PIN); \
if (V) port->PIO_SODR = mask; \
else port->PIO_CODR = mask; \
}while(0)
// Toggle a pin
#define _TOGGLE(IO) _WRITE(IO, !READ(IO))
#if MB(PRINTRBOARD_G2)
#include "fastio/G2_pins.h"
// Set pin as input
#define _SET_INPUT(IO) do{ \
pmc_enable_periph_clk(G2_g_APinDescription[IO].ulPeripheralId); \
PIO_Configure((DIO ## IO ## _WPORT), PIO_INPUT, MASK(DIO ## IO ## _PIN), 0); \
}while(0)
// Set pin as output
#define _SET_OUTPUT(IO) do{ \
uint32_t mask = MASK(G2_g_APinDescription[IO].ulPeripheralId); \
if ((PMC->PMC_PCSR0 & mask) != (mask)) PMC->PMC_PCER0 = mask; \
volatile Pio* port = (DIO ## IO ## _WPORT); \
mask = MASK(DIO ## IO ## _PIN); \
if (_READ(IO)) port->PIO_SODR = mask; \
else port->PIO_CODR = mask; \
port->PIO_IDR = mask; \
const uint32_t pin_config = G2_g_APinDescription[IO].ulPinConfiguration; \
if (pin_config & PIO_PULLUP) port->PIO_PUER = mask; \
else port->PIO_PUDR = mask; \
if (pin_config & PIO_OPENDRAIN) port->PIO_MDER = mask; \
else port->PIO_MDDR = mask; \
port->PIO_PER = mask; \
port->PIO_OER = mask; \
g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT; \
}while(0)
/**
* Set pin as output with comments
* #define _SET_OUTPUT(IO) do{ \
* uint32_t mask = MASK(G2_g_APinDescription[IO].ulPeripheralId); \
* if ((PMC->PMC_PCSR0 & mask ) != (mask)) PMC->PMC_PCER0 = mask; \ // enable PIO clock if not already enabled
*
* volatile Pio* port = (DIO ## IO ## _WPORT); \
* const uint32_t mask = MASK(DIO ## IO ## _PIN); \
* if (_READ(IO)) port->PIO_SODR = mask; \ // set output to match input BEFORE setting direction or will glitch the output
* else port->PIO_CODR = mask; \
*
* port->PIO_IDR = mask; \ // disable interrupt
*
* uint32_t pin_config = G2_g_APinDescription[IO].ulPinConfiguration; \
* if (pin_config & PIO_PULLUP) pPio->PIO_PUER = mask; \ // enable pullup if necessary
* else pPio->PIO_PUDR = mask; \
*
* if (pin_config & PIO_OPENDRAIN) port->PIO_MDER = mask; \ // Enable multi-drive if necessary
* else port->PIO_MDDR = mask; \
*
* port->PIO_PER = mask; \
* port->PIO_OER = mask; \ // set to output
*
* g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT; \
* }while(0)
*/
#else
// Set pin as input
#define _SET_INPUT(IO) do{ \
pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \
PIO_Configure(digitalPinToPort(IO), PIO_INPUT, digitalPinToBitMask(IO), 0); \
}while(0)
// Set pin as output
#define _SET_OUTPUT(IO) do{ \
pmc_enable_periph_clk(g_APinDescription[IO].ulPeripheralId); \
PIO_Configure(digitalPinToPort(IO), _READ(IO) ? PIO_OUTPUT_1 : PIO_OUTPUT_0, digitalPinToBitMask(IO), g_APinDescription[IO].ulPinConfiguration); \
g_pinStatus[IO] = (g_pinStatus[IO] & 0xF0) | PIN_STATUS_DIGITAL_OUTPUT; \
}while(0)
#endif
// Set pin as input with pullup mode
#define _PULLUP(IO,V) pinMode(IO, (V) ? INPUT_PULLUP : INPUT)
// Read a pin (wrapper)
#define READ(IO) _READ(IO)
// Write to a pin (wrapper)
#define WRITE(IO,V) _WRITE(IO,V)
// Toggle a pin (wrapper)
#define TOGGLE(IO) _TOGGLE(IO)
// Set pin as input (wrapper)
#define SET_INPUT(IO) _SET_INPUT(IO)
// Set pin as input with pullup (wrapper)
#define SET_INPUT_PULLUP(IO) do{ _SET_INPUT(IO); _PULLUP(IO, HIGH); }while(0)
// Set pin as input with pulldown (substitution)
#define SET_INPUT_PULLDOWN SET_INPUT
// Set pin as output (wrapper) - reads the pin and sets the output to that value
#define SET_OUTPUT(IO) _SET_OUTPUT(IO)
// Set pin as PWM
#define SET_PWM SET_OUTPUT
// Check if pin is an input
#define IS_INPUT(IO) ((digitalPinToPort(IO)->PIO_OSR & digitalPinToBitMask(IO)) == 0)
// Check if pin is an output
#define IS_OUTPUT(IO) ((digitalPinToPort(IO)->PIO_OSR & digitalPinToBitMask(IO)) != 0)
// Shorthand
#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
// digitalRead/Write wrappers
#define extDigitalRead(IO) digitalRead(IO)
#define extDigitalWrite(IO,V) digitalWrite(IO,V)
/**
* Ports and functions
* Added as necessary or if I feel like it- not a comprehensive list!
*/
// UART
#define RXD DIO0
#define TXD DIO1
// TWI (I2C)
#define SCL DIO21
#define SDA DIO20
/**
* pins
*/
#define DIO0_PIN 8
#define DIO0_WPORT PIOA
#define DIO1_PIN 9
#define DIO1_WPORT PIOA
#define DIO2_PIN 25
#define DIO2_WPORT PIOB
#define DIO3_PIN 28
#define DIO3_WPORT PIOC
#define DIO4_PIN 26
#define DIO4_WPORT PIOC
#define DIO5_PIN 25
#define DIO5_WPORT PIOC
#define DIO6_PIN 24
#define DIO6_WPORT PIOC
#define DIO7_PIN 23
#define DIO7_WPORT PIOC
#define DIO8_PIN 22
#define DIO8_WPORT PIOC
#define DIO9_PIN 21
#define DIO9_WPORT PIOC
#define DIO10_PIN 29
#define DIO10_WPORT PIOC
#define DIO11_PIN 7
#define DIO11_WPORT PIOD
#define DIO12_PIN 8
#define DIO12_WPORT PIOD
#define DIO13_PIN 27
#define DIO13_WPORT PIOB
#define DIO14_PIN 4
#define DIO14_WPORT PIOD
#define DIO15_PIN 5
#define DIO15_WPORT PIOD
#define DIO16_PIN 13
#define DIO16_WPORT PIOA
#define DIO17_PIN 12
#define DIO17_WPORT PIOA
#define DIO18_PIN 11
#define DIO18_WPORT PIOA
#define DIO19_PIN 10
#define DIO19_WPORT PIOA
#define DIO20_PIN 12
#define DIO20_WPORT PIOB
#define DIO21_PIN 13
#define DIO21_WPORT PIOB
#define DIO22_PIN 26
#define DIO22_WPORT PIOB
#define DIO23_PIN 14
#define DIO23_WPORT PIOA
#define DIO24_PIN 15
#define DIO24_WPORT PIOA
#define DIO25_PIN 0
#define DIO25_WPORT PIOD
#define DIO26_PIN 1
#define DIO26_WPORT PIOD
#define DIO27_PIN 2
#define DIO27_WPORT PIOD
#define DIO28_PIN 3
#define DIO28_WPORT PIOD
#define DIO29_PIN 6
#define DIO29_WPORT PIOD
#define DIO30_PIN 9
#define DIO30_WPORT PIOD
#define DIO31_PIN 7
#define DIO31_WPORT PIOA
#define DIO32_PIN 10
#define DIO32_WPORT PIOD
#define DIO33_PIN 1
#define DIO33_WPORT PIOC
#if !MB(PRINTRBOARD_G2) // normal DUE pin mapping
#define DIO34_PIN 2
#define DIO34_WPORT PIOC
#define DIO35_PIN 3
#define DIO35_WPORT PIOC
#define DIO36_PIN 4
#define DIO36_WPORT PIOC
#define DIO37_PIN 5
#define DIO37_WPORT PIOC
#define DIO38_PIN 6
#define DIO38_WPORT PIOC
#define DIO39_PIN 7
#define DIO39_WPORT PIOC
#define DIO40_PIN 8
#define DIO40_WPORT PIOC
#define DIO41_PIN 9
#define DIO41_WPORT PIOC
#endif // !PRINTRBOARD_G2
#define DIO42_PIN 19
#define DIO42_WPORT PIOA
#define DIO43_PIN 20
#define DIO43_WPORT PIOA
#define DIO44_PIN 19
#define DIO44_WPORT PIOC
#define DIO45_PIN 18
#define DIO45_WPORT PIOC
#define DIO46_PIN 17
#define DIO46_WPORT PIOC
#define DIO47_PIN 16
#define DIO47_WPORT PIOC
#define DIO48_PIN 15
#define DIO48_WPORT PIOC
#define DIO49_PIN 14
#define DIO49_WPORT PIOC
#define DIO50_PIN 13
#define DIO50_WPORT PIOC
#define DIO51_PIN 12
#define DIO51_WPORT PIOC
#define DIO52_PIN 21
#define DIO52_WPORT PIOB
#define DIO53_PIN 14
#define DIO53_WPORT PIOB
#define DIO54_PIN 16
#define DIO54_WPORT PIOA
#define DIO55_PIN 24
#define DIO55_WPORT PIOA
#define DIO56_PIN 23
#define DIO56_WPORT PIOA
#define DIO57_PIN 22
#define DIO57_WPORT PIOA
#define DIO58_PIN 6
#define DIO58_WPORT PIOA
#define DIO59_PIN 4
#define DIO59_WPORT PIOA
#define DIO60_PIN 3
#define DIO60_WPORT PIOA
#define DIO61_PIN 2
#define DIO61_WPORT PIOA
#define DIO62_PIN 17
#define DIO62_WPORT PIOB
#define DIO63_PIN 18
#define DIO63_WPORT PIOB
#define DIO64_PIN 19
#define DIO64_WPORT PIOB
#define DIO65_PIN 20
#define DIO65_WPORT PIOB
#define DIO66_PIN 15
#define DIO66_WPORT PIOB
#define DIO67_PIN 16
#define DIO67_WPORT PIOB
#define DIO68_PIN 1
#define DIO68_WPORT PIOA
#define DIO69_PIN 0
#define DIO69_WPORT PIOA
#define DIO70_PIN 17
#define DIO70_WPORT PIOA
#define DIO71_PIN 18
#define DIO71_WPORT PIOA
#define DIO72_PIN 30
#define DIO72_WPORT PIOC
#define DIO73_PIN 21
#define DIO73_WPORT PIOA
#define DIO74_PIN 25
#define DIO74_WPORT PIOA
#define DIO75_PIN 26
#define DIO75_WPORT PIOA
#define DIO76_PIN 27
#define DIO76_WPORT PIOA
#define DIO77_PIN 28
#define DIO77_WPORT PIOA
#define DIO78_PIN 23
#define DIO78_WPORT PIOB
#define DIO79_PIN 17
#define DIO79_WPORT PIOA
#define DIO80_PIN 12
#define DIO80_WPORT PIOB
#define DIO81_PIN 8
#define DIO81_WPORT PIOA
#define DIO82_PIN 11
#define DIO82_WPORT PIOA
#define DIO83_PIN 13
#define DIO83_WPORT PIOA
#define DIO84_PIN 4
#define DIO84_WPORT PIOD
#define DIO85_PIN 11
#define DIO85_WPORT PIOB
#define DIO86_PIN 21
#define DIO86_WPORT PIOB
#define DIO87_PIN 29
#define DIO87_WPORT PIOA
#define DIO88_PIN 15
#define DIO88_WPORT PIOB
#define DIO89_PIN 14
#define DIO89_WPORT PIOB
#define DIO90_PIN 1
#define DIO90_WPORT PIOA
#define DIO91_PIN 15
#define DIO91_WPORT PIOB
#ifdef ARDUINO_SAM_ARCHIM
#define DIO92_PIN 11
#define DIO92_WPORT PIOC
#define DIO93_PIN 2
#define DIO93_WPORT PIOB
#define DIO94_PIN 1
#define DIO94_WPORT PIOB
#define DIO95_PIN 0
#define DIO95_WPORT PIOB
#define DIO96_PIN 10
#define DIO96_WPORT PIOC
#define DIO97_PIN 24
#define DIO97_WPORT PIOB
#define DIO98_PIN 7
#define DIO98_WPORT PIOB
#define DIO99_PIN 6
#define DIO99_WPORT PIOB
#define DIO100_PIN 8
#define DIO100_WPORT PIOB
#define DIO101_PIN 5
#define DIO101_WPORT PIOB
#define DIO102_PIN 4
#define DIO102_WPORT PIOB
#define DIO103_PIN 3
#define DIO103_WPORT PIOB
#define DIO104_PIN 20
#define DIO104_WPORT PIOC
#define DIO105_PIN 22
#define DIO105_WPORT PIOB
#define DIO106_PIN 27
#define DIO106_WPORT PIOC
#define DIO107_PIN 10
#define DIO107_WPORT PIOB
#define DIO108_PIN 9
#define DIO108_WPORT PIOB
#else // !ARDUINO_SAM_ARCHIM
#define DIO92_PIN 5
#define DIO92_WPORT PIOA
#define DIO93_PIN 12
#define DIO93_WPORT PIOB
#define DIO94_PIN 22
#define DIO94_WPORT PIOB
#define DIO95_PIN 23
#define DIO95_WPORT PIOB
#define DIO96_PIN 24
#define DIO96_WPORT PIOB
#define DIO97_PIN 20
#define DIO97_WPORT PIOC
#define DIO98_PIN 27
#define DIO98_WPORT PIOC
#define DIO99_PIN 10
#define DIO99_WPORT PIOC
#define DIO100_PIN 11
#define DIO100_WPORT PIOC
#endif // !ARDUINO_SAM_ARCHIM

View File

@ -0,0 +1,206 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* The PWM module is only used to generate interrupts at specified times. It
* is NOT used to directly toggle pins. The ISR writes to the pin assigned to
* that interrupt.
*
* All PWMs use the same repetition rate. The G2 needs about 10kHz min in order to
* not have obvious ripple on the Vref signals.
*
* The data structures are setup to minimize the computation done by the ISR which
* minimizes ISR execution time. Execution times are 0.8 to 1.1 microseconds.
*
* FIve PWM interrupt sources are used. Channel 0 sets the base period. All Vref
* signals are set active when this counter overflows and resets to zero. The compare
* values in channels 1-4 are set to give the desired duty cycle for that Vref pin.
* When counter 0 matches the compare value then that channel generates an interrupt.
* The ISR checks the source of the interrupt and sets the corresponding pin inactive.
*
* Some jitter in the Vref signal is OK so the interrupt priority is left at its default value.
*/
#include "../../../inc/MarlinConfig.h"
#if MB(PRINTRBOARD_G2)
#include "G2_PWM.h"
#if PIN_EXISTS(MOTOR_CURRENT_PWM_X)
#define G2_PWM_X 1
#else
#define G2_PWM_X 0
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Y)
#define G2_PWM_Y 1
#else
#define G2_PWM_Y 0
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Z)
#define G2_PWM_Z 1
#else
#define G2_PWM_Z 0
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_E)
#define G2_PWM_E 1
#else
#define G2_PWM_E 0
#endif
#define G2_MASK_X(V) (G2_PWM_X * (V))
#define G2_MASK_Y(V) (G2_PWM_Y * (V))
#define G2_MASK_Z(V) (G2_PWM_Z * (V))
#define G2_MASK_E(V) (G2_PWM_E * (V))
volatile uint32_t *SODR_A = &PIOA->PIO_SODR,
*SODR_B = &PIOB->PIO_SODR,
*CODR_A = &PIOA->PIO_CODR,
*CODR_B = &PIOB->PIO_CODR;
PWM_map ISR_table[NUM_PWMS] = PWM_MAP_INIT;
void Stepper::digipot_init() {
#if PIN_EXISTS(MOTOR_CURRENT_PWM_X)
OUT_WRITE(MOTOR_CURRENT_PWM_X_PIN, 0); // init pins
#endif
#if PIN_EXISTS(MOTOR_CURRENT_PWM_Y)
OUT_WRITE(MOTOR_CURRENT_PWM_Y_PIN, 0);
#endif
#if G2_PWM_Z
OUT_WRITE(MOTOR_CURRENT_PWM_Z_PIN, 0);
#endif
#if G2_PWM_E
OUT_WRITE(MOTOR_CURRENT_PWM_E_PIN, 0);
#endif
#define WPKEY (0x50574D << 8) // “PWM” in ASCII
#define WPCMD_DIS_SW 0 // command to disable Write Protect SW
#define WPRG_ALL (PWM_WPCR_WPRG0 | PWM_WPCR_WPRG1 | PWM_WPCR_WPRG2 | PWM_WPCR_WPRG3 | PWM_WPCR_WPRG4 | PWM_WPCR_WPRG5) // all Write Protect Groups
#define PWM_CLOCK_F F_CPU / 1000000UL // set clock to 1MHz
PMC->PMC_PCER1 = PMC_PCER1_PID36; // enable PWM controller clock (disabled on power up)
PWM->PWM_WPCR = WPKEY | WPRG_ALL | WPCMD_DIS_SW; // enable setting of all PWM registers
PWM->PWM_CLK = PWM_CLOCK_F; // enable CLK_A and set it to 1MHz, leave CLK_B disabled
PWM->PWM_CH_NUM[0].PWM_CMR = 0b1011; // set channel 0 to Clock A input & to left aligned
if (G2_PWM_X) PWM->PWM_CH_NUM[1].PWM_CMR = 0b1011; // set channel 1 to Clock A input & to left aligned
if (G2_PWM_Y) PWM->PWM_CH_NUM[2].PWM_CMR = 0b1011; // set channel 2 to Clock A input & to left aligned
if (G2_PWM_Z) PWM->PWM_CH_NUM[3].PWM_CMR = 0b1011; // set channel 3 to Clock A input & to left aligned
if (G2_PWM_E) PWM->PWM_CH_NUM[4].PWM_CMR = 0b1011; // set channel 4 to Clock A input & to left aligned
PWM->PWM_CH_NUM[0].PWM_CPRD = PWM_PERIOD_US; // set channel 0 Period
PWM->PWM_IER2 = PWM_IER1_CHID0; // generate interrupt when counter0 overflows
PWM->PWM_IER2 = PWM_IER2_CMPM0
| G2_MASK_X(PWM_IER2_CMPM1)
| G2_MASK_Y(PWM_IER2_CMPM2)
| G2_MASK_Z(PWM_IER2_CMPM3)
| G2_MASK_E(PWM_IER2_CMPM4)
; // generate interrupt on compare event
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[0])); // interrupt when counter0 == CMPV - used to set Motor 1 PWM inactive
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[0])); // interrupt when counter0 == CMPV - used to set Motor 2 PWM inactive
if (G2_PWM_Z) PWM->PWM_CMP[3].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[1])); // interrupt when counter0 == CMPV - used to set Motor 3 PWM inactive
if (G2_PWM_E) PWM->PWM_CMP[4].PWM_CMPV = 0x010000000LL | G2_VREF_COUNT(G2_VREF(motor_current_setting[2])); // interrupt when counter0 == CMPV - used to set Motor 4 PWM inactive
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPM = 0x0001; // enable compare event
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPM = 0x0001; // enable compare event
if (G2_PWM_Z) PWM->PWM_CMP[3].PWM_CMPM = 0x0001; // enable compare event
if (G2_PWM_E) PWM->PWM_CMP[4].PWM_CMPM = 0x0001; // enable compare event
PWM->PWM_SCM = PWM_SCM_UPDM_MODE0 | PWM_SCM_SYNC0
| G2_MASK_X(PWM_SCM_SYNC1)
| G2_MASK_Y(PWM_SCM_SYNC2)
| G2_MASK_Z(PWM_SCM_SYNC3)
| G2_MASK_E(PWM_SCM_SYNC4)
; // sync 1-4 with 0, use mode 0 for updates
PWM->PWM_ENA = PWM_ENA_CHID0
| G2_MASK_X(PWM_ENA_CHID1)
| G2_MASK_Y(PWM_ENA_CHID2)
| G2_MASK_Z(PWM_ENA_CHID3)
| G2_MASK_E(PWM_ENA_CHID4)
; // enable channels used by G2
PWM->PWM_IER1 = PWM_IER1_CHID0
| G2_MASK_X(PWM_IER1_CHID1)
| G2_MASK_Y(PWM_IER1_CHID2)
| G2_MASK_Z(PWM_IER1_CHID3)
| G2_MASK_E(PWM_IER1_CHID4)
; // enable interrupts for channels used by G2
NVIC_EnableIRQ(PWM_IRQn); // Enable interrupt handler
NVIC_SetPriority(PWM_IRQn, NVIC_EncodePriority(0, 10, 0)); // normal priority for PWM module (can stand some jitter on the Vref signals)
}
void Stepper::set_digipot_current(const uint8_t driver, const int16_t current) {
if (!(PWM->PWM_CH_NUM[0].PWM_CPRD == PWM_PERIOD_US)) digipot_init(); // Init PWM system if needed
switch (driver) {
case 0:
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current)); // update X & Y
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current));
if (G2_PWM_X) PWM->PWM_CMP[1].PWM_CMPMUPD = 0x0001; // enable compare event
if (G2_PWM_Y) PWM->PWM_CMP[2].PWM_CMPMUPD = 0x0001; // enable compare event
if (G2_PWM_X || G2_PWM_Y) PWM->PWM_SCUC = PWM_SCUC_UPDULOCK; // tell the PWM controller to update the values on the next cycle
break;
case 1:
if (G2_PWM_Z) {
PWM->PWM_CMP[3].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current)); // update Z
PWM->PWM_CMP[3].PWM_CMPMUPD = 0x0001; // enable compare event
PWM->PWM_SCUC = PWM_SCUC_UPDULOCK; // tell the PWM controller to update the values on the next cycle
}
break;
default:
if (G2_PWM_E) {
PWM->PWM_CMP[4].PWM_CMPVUPD = 0x010000000LL | G2_VREF_COUNT(G2_VREF(current)); // update E
PWM->PWM_CMP[4].PWM_CMPMUPD = 0x0001; // enable compare event
PWM->PWM_SCUC = PWM_SCUC_UPDULOCK; // tell the PWM controller to update the values on the next cycle
}
break;
}
}
volatile uint32_t PWM_ISR1_STATUS, PWM_ISR2_STATUS;
void PWM_Handler() {
PWM_ISR1_STATUS = PWM->PWM_ISR1;
PWM_ISR2_STATUS = PWM->PWM_ISR2;
if (PWM_ISR1_STATUS & PWM_IER1_CHID0) { // CHAN_0 interrupt
if (G2_PWM_X) *ISR_table[0].set_register = ISR_table[0].write_mask; // set X to active
if (G2_PWM_Y) *ISR_table[1].set_register = ISR_table[1].write_mask; // set Y to active
if (G2_PWM_Z) *ISR_table[2].set_register = ISR_table[2].write_mask; // set Z to active
if (G2_PWM_E) *ISR_table[3].set_register = ISR_table[3].write_mask; // set E to active
}
else {
if (G2_PWM_X && (PWM_ISR2_STATUS & PWM_IER2_CMPM1)) *ISR_table[0].clr_register = ISR_table[0].write_mask; // set X to inactive
if (G2_PWM_Y && (PWM_ISR2_STATUS & PWM_IER2_CMPM2)) *ISR_table[1].clr_register = ISR_table[1].write_mask; // set Y to inactive
if (G2_PWM_Z && (PWM_ISR2_STATUS & PWM_IER2_CMPM3)) *ISR_table[2].clr_register = ISR_table[2].write_mask; // set Z to inactive
if (G2_PWM_E && (PWM_ISR2_STATUS & PWM_IER2_CMPM4)) *ISR_table[3].clr_register = ISR_table[3].write_mask; // set E to inactive
}
return;
}
#endif // PRINTRBOARD_G2

View File

@ -0,0 +1,78 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* This module is stripped down version of the LPC1768_PWM.h file from
* PR #7500. It is hardwired for the PRINTRBOARD_G2 Motor Current needs.
*/
#include "../../../inc/MarlinConfigPre.h"
#include "../../../module/stepper.h"
//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\module\stepper.h
//C:\Users\bobku\Documents\GitHub\Marlin-Bob-2\Marlin\src\HAL\HAL_DUE\G2_PWM.h
#define PWM_PERIOD_US 100 // base repetition rate in micro seconds
typedef struct { // holds the data needed by the ISR to control the Vref pin
volatile uint32_t* set_register;
volatile uint32_t* clr_register;
uint32_t write_mask;
} PWM_map;
#define G2_VREF(I) (uint32_t)(I * 5 * 0.15) // desired Vref * 1000 (scaled so don't loose accuracy in next step)
#define G2_VREF_COUNT(Q) (uint32_t)map(constrain(Q, 500, 3.3 * 1000), 0, 3.3 * 1000, 0, PWM_PERIOD_US) // under 500 the results are very non-linear
extern volatile uint32_t *SODR_A, *SODR_B, *CODR_A, *CODR_B;
#define _PIN(IO) (DIO ## IO ## _PIN)
#define PWM_MAP_INIT_ROW(IO,ZZ) { ZZ == 'A' ? SODR_A : SODR_B, ZZ == 'A' ? CODR_A : CODR_B, 1 << _PIN(IO) }
#define PWM_MAP_INIT { PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_X_PIN, 'B'), \
PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_Y_PIN, 'B'), \
PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_Z_PIN, 'B'), \
PWM_MAP_INIT_ROW(MOTOR_CURRENT_PWM_E_PIN, 'A'), \
};
#define NUM_PWMS 4
extern PWM_map ISR_table[NUM_PWMS];
extern uint32_t motor_current_setting[3];
#define IR_BIT(p) (WITHIN(p, 0, 3) ? (p) : (p) + 4)
#define COPY_ACTIVE_TABLE() do{ LOOP_L_N(i, 6) work_table[i] = active_table[i]; }while(0)
#define PWM_MR0 19999 // base repetition rate minus one count - 20mS
#define PWM_PR 24 // prescaler value - prescaler divide by 24 + 1 - 1 MHz output
#define PWM_PCLKSEL0 0x00 // select clock source for prescaler - defaults to 25MHz on power up
// 0: 25MHz, 1: 100MHz, 2: 50MHz, 3: 12.5MHZ to PWM1 prescaler
#define MR0_MARGIN 200 // if channel value too close to MR0 the system locks up
extern bool PWM_table_swap; // flag to tell the ISR that the tables have been swapped
#define HAL_G2_PWM_ISR void PWM_Handler()
extern volatile uint32_t PWM_ISR1_STATUS, PWM_ISR2_STATUS;

View File

@ -0,0 +1,278 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdint.h>
/**
* This file contains the custom port/pin definitions for the PRINTRBOARD_G2
* motherboard. This motherboard uses the SAM3X8C which is a subset of the
* SAM3X8E used in the DUE board. It uses port/pin pairs that are not
* available using the DUE definitions.
*
* The first part is a copy of the pin descriptions in the
* "variants\arduino_due_x\variant.cpp" file but with pins 34-41 replaced by
* the G2 pins.
*
* The second part is the FASTIO port/pin definitions.
*
* THESE PINS CAN ONLY BE ACCESSED VIA FASTIO COMMANDS.
*/
/*
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
*/
typedef struct _G2_PinDescription {
Pio* pPort;
uint32_t ulPin;
uint32_t ulPeripheralId;
EPioType ulPinType;
uint32_t ulPinConfiguration;
uint32_t ulPinAttribute;
EAnalogChannel ulAnalogChannel; /* Analog pin in the Arduino context (label on the board) */
EAnalogChannel ulADCChannelNumber; /* ADC Channel number in the SAM device */
EPWMChannel ulPWMChannel;
ETCChannel ulTCChannel;
} G2_PinDescription;
/**
* This section is a copy of the pin descriptions in the "variants\arduino_due_x\variant.cpp" file
* with pins 34-41 replaced by the G2 pins.
*/
/**
* Pins descriptions
*/
const G2_PinDescription G2_g_APinDescription[] = {
// 0 .. 53 - Digital pins
// ----------------------
// 0/1 - UART (Serial)
{ PIOA, PIO_PA8A_URXD, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // URXD
{ PIOA, PIO_PA9A_UTXD, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // UTXD
// 2
{ PIOB, PIO_PB25B_TIOA0, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC0_CHA0 }, // TIOA0
{ PIOC, PIO_PC28B_TIOA7, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHA7 }, // TIOA7
{ PIOC, PIO_PC26B_TIOB6, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHB6 }, // TIOB6
// 5
{ PIOC, PIO_PC25B_TIOA6, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHA6 }, // TIOA6
{ PIOC, PIO_PC24B_PWML7, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH7, NOT_ON_TIMER }, // PWML7
{ PIOC, PIO_PC23B_PWML6, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH6, NOT_ON_TIMER }, // PWML6
{ PIOC, PIO_PC22B_PWML5, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH5, NOT_ON_TIMER }, // PWML5
{ PIOC, PIO_PC21B_PWML4, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), NO_ADC, NO_ADC, PWM_CH4, NOT_ON_TIMER }, // PWML4
// 10
{ PIOC, PIO_PC29B_TIOB7, ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHB7 }, // TIOB7
{ PIOD, PIO_PD7B_TIOA8, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHA8 }, // TIOA8
{ PIOD, PIO_PD8B_TIOB8, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC2_CHB8 }, // TIOB8
// 13 - AMBER LED
{ PIOB, PIO_PB27B_TIOB0, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_TIMER), NO_ADC, NO_ADC, NOT_ON_PWM, TC0_CHB0 }, // TIOB0
// 14/15 - USART3 (Serial3)
{ PIOD, PIO_PD4B_TXD3, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TXD3
{ PIOD, PIO_PD5B_RXD3, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // RXD3
// 16/17 - USART1 (Serial2)
{ PIOA, PIO_PA13A_TXD1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TXD1
{ PIOA, PIO_PA12A_RXD1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // RXD1
// 18/19 - USART0 (Serial1)
{ PIOA, PIO_PA11A_TXD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TXD0
{ PIOA, PIO_PA10A_RXD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // RXD0
// 20/21 - TWI1
{ PIOB, PIO_PB12A_TWD1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWD1 - SDA0
{ PIOB, PIO_PB13A_TWCK1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWCK1 - SCL0
// 22
{ PIOB, PIO_PB26, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 22
{ PIOA, PIO_PA14, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 23
{ PIOA, PIO_PA15, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 24
{ PIOD, PIO_PD0, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 25
// 26
{ PIOD, PIO_PD1, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 26
{ PIOD, PIO_PD2, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 27
{ PIOD, PIO_PD3, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 28
{ PIOD, PIO_PD6, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 29
// 30
{ PIOD, PIO_PD9, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 30
{ PIOA, PIO_PA7, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 31
{ PIOD, PIO_PD10, ID_PIOD, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 32
{ PIOC, PIO_PC1, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 33
// 34
// start of custom pins
{ PIOA, PIO_PA29, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 34 Y_STEP_PIN
{ PIOB, PIO_PB1, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 35 Y_DIR_PIN
{ PIOB, PIO_PB0, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 36 Y_ENABLE_PIN
{ PIOB, PIO_PB22, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 37 E0_ENABLE_PIN
{ PIOB, PIO_PB11, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 38 E0_MS1_PIN
{ PIOB, PIO_PB10, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 39 E0_MS3_PIN
{ PIOA, PIO_PA5, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 40 HEATER_0_PIN
{ PIOB, PIO_PB24, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 41 HEATER_BED_PIN
// end of custom pins
// 42
{ PIOA, PIO_PA19, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 42
{ PIOA, PIO_PA20, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 43
{ PIOC, PIO_PC19, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 44
{ PIOC, PIO_PC18, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 45
// 46
{ PIOC, PIO_PC17, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 46
{ PIOC, PIO_PC16, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 47
{ PIOC, PIO_PC15, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 48
{ PIOC, PIO_PC14, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 49
// 50
{ PIOC, PIO_PC13, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 50
{ PIOC, PIO_PC12, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 51
{ PIOB, PIO_PB21, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 52
{ PIOB, PIO_PB14, ID_PIOB, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // PIN 53
// 54 .. 65 - Analog pins
// ----------------------
{ PIOA, PIO_PA16X1_AD7, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC0, ADC7, NOT_ON_PWM, NOT_ON_TIMER }, // AD0
{ PIOA, PIO_PA24X1_AD6, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC1, ADC6, NOT_ON_PWM, NOT_ON_TIMER }, // AD1
{ PIOA, PIO_PA23X1_AD5, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC2, ADC5, NOT_ON_PWM, NOT_ON_TIMER }, // AD2
{ PIOA, PIO_PA22X1_AD4, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC3, ADC4, NOT_ON_PWM, NOT_ON_TIMER }, // AD3
// 58
{ PIOA, PIO_PA6X1_AD3, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC4, ADC3, NOT_ON_PWM, TC0_CHB2 }, // AD4
{ PIOA, PIO_PA4X1_AD2, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC5, ADC2, NOT_ON_PWM, NOT_ON_TIMER }, // AD5
{ PIOA, PIO_PA3X1_AD1, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC6, ADC1, NOT_ON_PWM, TC0_CHB1 }, // AD6
{ PIOA, PIO_PA2X1_AD0, ID_PIOA, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC7, ADC0, NOT_ON_PWM, TC0_CHA1 }, // AD7
// 62
{ PIOB, PIO_PB17X1_AD10, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC8, ADC10, NOT_ON_PWM, NOT_ON_TIMER }, // AD8
{ PIOB, PIO_PB18X1_AD11, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC9, ADC11, NOT_ON_PWM, NOT_ON_TIMER }, // AD9
{ PIOB, PIO_PB19X1_AD12, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC10, ADC12, NOT_ON_PWM, NOT_ON_TIMER }, // AD10
{ PIOB, PIO_PB20X1_AD13, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC11, ADC13, NOT_ON_PWM, NOT_ON_TIMER }, // AD11
// 66/67 - DAC0/DAC1
{ PIOB, PIO_PB15X1_DAC0, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC12, DA0, NOT_ON_PWM, NOT_ON_TIMER }, // DAC0
{ PIOB, PIO_PB16X1_DAC1, ID_PIOB, PIO_INPUT, PIO_DEFAULT, PIN_ATTR_ANALOG, ADC13, DA1, NOT_ON_PWM, NOT_ON_TIMER }, // DAC1
// 68/69 - CANRX0/CANTX0
{ PIOA, PIO_PA1A_CANRX0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, ADC14, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANRX
{ PIOA, PIO_PA0A_CANTX0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, ADC15, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANTX
// 70/71 - TWI0
{ PIOA, PIO_PA17A_TWD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWD0 - SDA1
{ PIOA, PIO_PA18A_TWCK0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // TWCK0 - SCL1
// 72/73 - LEDs
{ PIOC, PIO_PC30, ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // LED AMBER RXL
{ PIOA, PIO_PA21, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // LED AMBER TXL
// 74/75/76 - SPI
{ PIOA, PIO_PA25A_SPI0_MISO,ID_PIOA,PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // MISO
{ PIOA, PIO_PA26A_SPI0_MOSI,ID_PIOA,PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // MOSI
{ PIOA, PIO_PA27A_SPI0_SPCK,ID_PIOA,PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // SPCK
// 77 - SPI CS0
{ PIOA, PIO_PA28A_SPI0_NPCS0,ID_PIOA,PIO_PERIPH_A,PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS0
// 78 - SPI CS3 (unconnected)
{ PIOB, PIO_PB23B_SPI0_NPCS3,ID_PIOB,PIO_PERIPH_B,PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS3
// 79 .. 84 - "All pins" masks
// 79 - TWI0 all pins
{ PIOA, PIO_PA17A_TWD0|PIO_PA18A_TWCK0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 80 - TWI1 all pins
{ PIOB, PIO_PB12A_TWD1|PIO_PB13A_TWCK1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 81 - UART (Serial) all pins
{ PIOA, PIO_PA8A_URXD|PIO_PA9A_UTXD, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 82 - USART0 (Serial1) all pins
{ PIOA, PIO_PA11A_TXD0|PIO_PA10A_RXD0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 83 - USART1 (Serial2) all pins
{ PIOA, PIO_PA13A_TXD1|PIO_PA12A_RXD1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 84 - USART3 (Serial3) all pins
{ PIOD, PIO_PD4B_TXD3|PIO_PD5B_RXD3, ID_PIOD, PIO_PERIPH_B, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 85 - USB
{ PIOB, PIO_PB11A_UOTGID|PIO_PB10A_UOTGVBOF, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL,NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // ID - VBOF
// 86 - SPI CS2
{ PIOB, PIO_PB21B_SPI0_NPCS2, ID_PIOB, PIO_PERIPH_B, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS2
// 87 - SPI CS1
{ PIOA, PIO_PA29A_SPI0_NPCS1, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // NPCS1
// 88/89 - CANRX1/CANTX1 (same physical pin for 66/53)
{ PIOB, PIO_PB15A_CANRX1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANRX1
{ PIOB, PIO_PB14A_CANTX1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, PIN_ATTR_DIGITAL, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }, // CANTX1
// 90 .. 91 - "All CAN pins" masks
// 90 - CAN0 all pins
{ PIOA, PIO_PA1A_CANRX0|PIO_PA0A_CANTX0, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// 91 - CAN1 all pins
{ PIOB, PIO_PB15A_CANRX1|PIO_PB14A_CANTX1, ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT, (PIN_ATTR_DIGITAL|PIN_ATTR_COMBO), NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER },
// END
{ nullptr, 0, 0, PIO_NOT_A_PIN, PIO_DEFAULT, 0, NO_ADC, NO_ADC, NOT_ON_PWM, NOT_ON_TIMER }
};
// This section replaces the FASTIO definitions of pins 34-41
#define DIO34_PIN 29
#define DIO34_WPORT PIOA // only available via FASTIO // 34 PA29 - Y_STEP_PIN
#define DIO35_PIN 1
#define DIO35_WPORT PIOB // only available via FASTIO // 35 PAB1 - Y_DIR_PIN
#define DIO36_PIN 0
#define DIO36_WPORT PIOB // only available via FASTIO // 36 PB0 - Y_ENABLE_PIN
#define DIO37_PIN 22
#define DIO37_WPORT PIOB // only available via FASTIO // 37 PB22 - E0_ENABLE_PIN
#define DIO38_PIN 11
#define DIO38_WPORT PIOB // only available via FASTIO // 38 PB11 - E0_MS1_PIN
#define DIO39_PIN 10
#define DIO39_WPORT PIOB // only available via FASTIO // 39 PB10 - E0_MS3_PIN
#define DIO40_PIN 5
#define DIO40_WPORT PIOA // only available via FASTIO // 40 PA5 - HEATER_0_PIN
#define DIO41_PIN 24
#define DIO41_WPORT PIOB // only available via FASTIO // 41 PB24 - HEATER_BED_PIN

View File

@ -0,0 +1,26 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#if HAS_SPI_TFT || HAS_FSMC_TFT
#error "Sorry! TFT displays are not available for HAL/DUE."
#endif

View File

@ -0,0 +1,22 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once

View File

@ -0,0 +1,28 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#if USE_FALLBACK_EEPROM
#define FLASH_EEPROM_EMULATION
#elif EITHER(I2C_EEPROM, SPI_EEPROM)
#define USE_SHARED_EEPROM 1
#endif

View File

@ -0,0 +1,89 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Test Arduino Due specific configuration values for errors at compile-time.
*/
/**
* Check for common serial pin conflicts
*/
#define CHECK_SERIAL_PIN(N) ( \
X_STOP_PIN == N || Y_STOP_PIN == N || Z_STOP_PIN == N \
|| X_MIN_PIN == N || Y_MIN_PIN == N || Z_MIN_PIN == N \
|| X_MAX_PIN == N || Y_MAX_PIN == N || Z_MAX_PIN == N \
|| X_STEP_PIN == N || Y_STEP_PIN == N || Z_STEP_PIN == N \
|| X_DIR_PIN == N || Y_DIR_PIN == N || Z_DIR_PIN == N \
|| X_ENA_PIN == N || Y_ENA_PIN == N || Z_ENA_PIN == N \
)
#if CONF_SERIAL_IS(0) // D0-D1. No known conflicts.
#endif
#if CONF_SERIAL_IS(1) && (CHECK_SERIAL_PIN(18) || CHECK_SERIAL_PIN(19))
#error "Serial Port 1 pin D18 and/or D19 conflicts with another pin on the board."
#endif
#if CONF_SERIAL_IS(2) && (CHECK_SERIAL_PIN(16) || CHECK_SERIAL_PIN(17))
#error "Serial Port 2 pin D16 and/or D17 conflicts with another pin on the board."
#endif
#if CONF_SERIAL_IS(3) && (CHECK_SERIAL_PIN(14) || CHECK_SERIAL_PIN(15))
#error "Serial Port 3 pin D14 and/or D15 conflicts with another pin on the board."
#endif
#undef CHECK_SERIAL_PIN
/**
* HARDWARE VS. SOFTWARE SPI COMPATIBILITY
*
* DUE selects hardware vs. software SPI depending on whether one of the hardware-controllable SDSS pins is in use.
*
* The hardware SPI controller doesn't allow software SPIs to control any shared pins.
*
* When DUE software SPI is used then Trinamic drivers must use the TMC softSPI.
*
* When DUE hardware SPI is used then a Trinamic driver can use either its hardware SPI or, if there are no shared
* pins, its software SPI.
*
* Usually the hardware SPI pins are only available to the LCD. This makes the DUE hard SPI used at the same time
* as the TMC2130 soft SPI the most common setup.
*/
#define _IS_HW_SPI(P) (defined(TMC_SW_##P) && (TMC_SW_##P == SD_MOSI_PIN || TMC_SW_##P == SD_MISO_PIN || TMC_SW_##P == SD_SCK_PIN))
#if ENABLED(SDSUPPORT) && HAS_DRIVER(TMC2130)
#if ENABLED(TMC_USE_SW_SPI)
#if DISABLED(DUE_SOFTWARE_SPI) && (_IS_HW_SPI(MOSI) || _IS_HW_SPI(MISO) || _IS_HW_SPI(SCK))
#error "DUE hardware SPI is required but is incompatible with TMC2130 software SPI. Either disable TMC_USE_SW_SPI or use separate pins for the two SPIs."
#endif
#elif ENABLED(DUE_SOFTWARE_SPI)
#error "DUE software SPI is required but is incompatible with TMC2130 hardware SPI. Enable TMC_USE_SW_SPI to fix."
#endif
#endif
#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY
#error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on DUE."
#endif
#if HAS_TMC_SW_SERIAL
#error "TMC220x Software Serial is not supported on the DUE platform."
#endif
#if USING_PULLDOWNS
#error "PULLDOWN pin mode is not available on DUE boards."
#endif

185
src/HAL/DUE/pinsDebug.h Normal file
View File

@ -0,0 +1,185 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* Support routines for Due
*/
/**
* Translation of routines & variables used by pinsDebug.h
*/
#include "../shared/Marduino.h"
/**
* Due/Marlin quirks
*
* a) determining the state of a pin
* The Due/Arduino status definitions for the g_pinStatus[pin] array are:
* #define PIN_STATUS_DIGITAL_INPUT_PULLUP (0x01)
* #define PIN_STATUS_DIGITAL_INPUT (0x02)
* #define PIN_STATUS_DIGITAL_OUTPUT (0x03)
* #define PIN_STATUS_ANALOG (0x04)
* #define PIN_STATUS_PWM (0x05)
* #define PIN_STATUS_TIMER (0x06)
*
* These are only valid if the following Due/Arduino provided functions are used:
* analogRead
* analogWrite
* digitalWrite
* pinMode
*
* The FASTIO routines do not touch the g_pinStatus[pin] array.
*
* The net result is that both the g_pinStatus[pin] array and the PIO_OSR register
* needs to be looked at when determining if a pin is an input or an output.
*
* b) Due has only pins 6, 7, 8 & 9 enabled for PWMs. FYI - they run at 1kHz
*
* c) NUM_DIGITAL_PINS does not include the analog pins
*
* d) Pins 0-78 are defined for Due but 78 has a comment of "unconnected!". 78 is
* included just in case.
*/
#define NUMBER_PINS_TOTAL PINS_COUNT
#define digitalRead_mod(p) extDigitalRead(p) // AVR digitalRead disabled PWM before it read the pin
#define PRINT_PORT(p)
#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0)
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%02d"), p); SERIAL_ECHO(buffer); }while(0)
#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0)
#define GET_ARRAY_PIN(p) pin_array[p].pin
#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital
#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL ? 1 : 0)
#define DIGITAL_PIN_TO_ANALOG_PIN(p) int(p - analogInputToDigitalPin(0))
#define IS_ANALOG(P) WITHIN(P, char(analogInputToDigitalPin(0)), char(analogInputToDigitalPin(NUM_ANALOG_INPUTS - 1)))
#define pwm_status(pin) (((g_pinStatus[pin] & 0xF) == PIN_STATUS_PWM) && \
((g_APinDescription[pin].ulPinAttribute & PIN_ATTR_PWM) == PIN_ATTR_PWM))
#define MULTI_NAME_PAD 14 // space needed to be pretty if not first name assigned to a pin
bool GET_PINMODE(int8_t pin) { // 1: output, 0: input
volatile Pio* port = g_APinDescription[pin].pPort;
uint32_t mask = g_APinDescription[pin].ulPin;
uint8_t pin_status = g_pinStatus[pin] & 0xF;
return ( (pin_status == 0 && (port->PIO_OSR & mask))
|| pin_status == PIN_STATUS_DIGITAL_OUTPUT
|| pwm_status(pin));
}
void pwm_details(int32_t pin) {
if (pwm_status(pin)) {
uint32_t chan = g_APinDescription[pin].ulPWMChannel;
SERIAL_ECHOPGM("PWM = ", PWM_INTERFACE->PWM_CH_NUM[chan].PWM_CDTY);
}
}
/**
* DUE Board pin | PORT | Label
* ----------------+--------+-------
* 0 | PA8 | "RX0"
* 1 | PA9 | "TX0"
* 2 TIOA0 | PB25 |
* 3 TIOA7 | PC28 |
* 4 NPCS1 | PA29 |
* TIOB6 | PC26 |
* 5 TIOA6 | PC25 |
* 6 PWML7 | PC24 |
* 7 PWML6 | PC23 |
* 8 PWML5 | PC22 |
* 9 PWML4 | PC21 |
* 10 NPCS0 | PA28 |
* TIOB7 | PC29 |
* 11 TIOA8 | PD7 |
* 12 TIOB8 | PD8 |
* 13 TIOB0 | PB27 | LED AMBER "L"
* 14 TXD3 | PD4 | "TX3"
* 15 RXD3 | PD5 | "RX3"
* 16 TXD1 | PA13 | "TX2"
* 17 RXD1 | PA12 | "RX2"
* 18 TXD0 | PA11 | "TX1"
* 19 RXD0 | PA10 | "RX1"
* 20 | PB12 | "SDA"
* 21 | PB13 | "SCL"
* 22 | PB26 |
* 23 | PA14 |
* 24 | PA15 |
* 25 | PD0 |
* 26 | PD1 |
* 27 | PD2 |
* 28 | PD3 |
* 29 | PD6 |
* 30 | PD9 |
* 31 | PA7 |
* 32 | PD10 |
* 33 | PC1 |
* 34 | PC2 |
* 35 | PC3 |
* 36 | PC4 |
* 37 | PC5 |
* 38 | PC6 |
* 39 | PC7 |
* 40 | PC8 |
* 41 | PC9 |
* 42 | PA19 |
* 43 | PA20 |
* 44 | PC19 |
* 45 | PC18 |
* 46 | PC17 |
* 47 | PC16 |
* 48 | PC15 |
* 49 | PC14 |
* 50 | PC13 |
* 51 | PC12 |
* 52 NPCS2 | PB21 |
* 53 | PB14 |
* 54 | PA16 | "A0"
* 55 | PA24 | "A1"
* 56 | PA23 | "A2"
* 57 | PA22 | "A3"
* 58 TIOB2 | PA6 | "A4"
* 69 | PA4 | "A5"
* 60 TIOB1 | PA3 | "A6"
* 61 TIOA1 | PA2 | "A7"
* 62 | PB17 | "A8"
* 63 | PB18 | "A9"
* 64 | PB19 | "A10"
* 65 | PB20 | "A11"
* 66 | PB15 | "DAC0"
* 67 | PB16 | "DAC1"
* 68 | PA1 | "CANRX"
* 69 | PA0 | "CANTX"
* 70 | PA17 | "SDA1"
* 71 | PA18 | "SCL1"
* 72 | PC30 | LED AMBER "RX"
* 73 | PA21 | LED AMBER "TX"
* 74 MISO | PA25 |
* 75 MOSI | PA26 |
* 76 SCLK | PA27 |
* 77 NPCS0 | PA28 |
* 78 NPCS3 | PB23 | unconnected!
*
* USB pin | PORT
* ----------------+--------
* ID | PB11
* VBOF | PB10
*/

64
src/HAL/DUE/spi_pins.h Normal file
View File

@ -0,0 +1,64 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* Define SPI Pins: SCK, MISO, MOSI, SS
*
* Available chip select pins for HW SPI are 4 10 52 77
*/
#if SDSS == 4 || SDSS == 10 || SDSS == 52 || SDSS == 77 || SDSS == 87
#if SDSS == 4
#define SPI_PIN 87
#define SPI_CHAN 1
#elif SDSS == 10
#define SPI_PIN 77
#define SPI_CHAN 0
#elif SDSS == 52
#define SPI_PIN 86
#define SPI_CHAN 2
#elif SDSS == 77
#define SPI_PIN 77
#define SPI_CHAN 0
#else
#define SPI_PIN 87
#define SPI_CHAN 1
#endif
#define SD_SCK_PIN 76
#define SD_MISO_PIN 74
#define SD_MOSI_PIN 75
#else
// defaults
#define DUE_SOFTWARE_SPI
#ifndef SD_SCK_PIN
#define SD_SCK_PIN 52
#endif
#ifndef SD_MISO_PIN
#define SD_MISO_PIN 50
#endif
#ifndef SD_MOSI_PIN
#define SD_MOSI_PIN 51
#endif
#endif
/* A.28, A.29, B.21, C.26, C.29 */
#define SD_SS_PIN SDSS

139
src/HAL/DUE/timers.cpp Normal file
View File

@ -0,0 +1,139 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
* Copyright (c) 2015-2016 Nico Tonnhofer wurstnase.reprap@gmail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/**
* HAL Timers for Arduino Due and compatible (SAM3X8E)
*/
#ifdef ARDUINO_ARCH_SAM
// ------------------------
// Includes
// ------------------------
#include "../../inc/MarlinConfig.h"
#include "HAL.h"
// ------------------------
// Local defines
// ------------------------
#define NUM_HARDWARE_TIMERS 9
// ------------------------
// Private Variables
// ------------------------
const tTimerConfig timer_config[NUM_HARDWARE_TIMERS] = {
{ TC0, 0, TC0_IRQn, 3}, // 0 - [servo timer5]
{ TC0, 1, TC1_IRQn, 0}, // 1
{ TC0, 2, TC2_IRQn, 2}, // 2 - stepper
{ TC1, 0, TC3_IRQn, 0}, // 3 - stepper for BOARD_ARCHIM1
{ TC1, 1, TC4_IRQn, 15}, // 4 - temperature
{ TC1, 2, TC5_IRQn, 3}, // 5 - [servo timer3]
{ TC2, 0, TC6_IRQn, 14}, // 6 - tone
{ TC2, 1, TC7_IRQn, 0}, // 7
{ TC2, 2, TC8_IRQn, 0}, // 8
};
// ------------------------
// Public functions
// ------------------------
/*
Timer_clock1: Prescaler 2 -> 42MHz
Timer_clock2: Prescaler 8 -> 10.5MHz
Timer_clock3: Prescaler 32 -> 2.625MHz
Timer_clock4: Prescaler 128 -> 656.25kHz
*/
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
Tc *tc = timer_config[timer_num].pTimerRegs;
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
uint32_t channel = timer_config[timer_num].channel;
// Disable interrupt, just in case it was already enabled
NVIC_DisableIRQ(irq);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
// Disable timer interrupt
tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
// Stop timer, just in case, to be able to reconfigure it
TC_Stop(tc, channel);
pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)irq);
NVIC_SetPriority(irq, timer_config[timer_num].priority);
// wave mode, reset counter on match with RC,
TC_Configure(tc, channel,
TC_CMR_WAVE
| TC_CMR_WAVSEL_UP_RC
| (HAL_TIMER_PRESCALER == 2 ? TC_CMR_TCCLKS_TIMER_CLOCK1 : 0)
| (HAL_TIMER_PRESCALER == 8 ? TC_CMR_TCCLKS_TIMER_CLOCK2 : 0)
| (HAL_TIMER_PRESCALER == 32 ? TC_CMR_TCCLKS_TIMER_CLOCK3 : 0)
| (HAL_TIMER_PRESCALER == 128 ? TC_CMR_TCCLKS_TIMER_CLOCK4 : 0)
);
// Set compare value
TC_SetRC(tc, channel, VARIANT_MCK / (HAL_TIMER_PRESCALER) / frequency);
// And start timer
TC_Start(tc, channel);
// enable interrupt on RC compare
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPCS;
// Finally, enable IRQ
NVIC_EnableIRQ(irq);
}
void HAL_timer_enable_interrupt(const uint8_t timer_num) {
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
NVIC_EnableIRQ(irq);
}
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
NVIC_DisableIRQ(irq);
// We NEED memory barriers to ensure Interrupts are actually disabled!
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
__DSB();
__ISB();
}
// missing from CMSIS: Check if interrupt is enabled or not
static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
}
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
IRQn_Type irq = timer_config[timer_num].IRQ_Id;
return NVIC_GetEnabledIRQ(irq);
}
#endif // ARDUINO_ARCH_SAM

129
src/HAL/DUE/timers.h Normal file
View File

@ -0,0 +1,129 @@
/**
* Marlin 3D Printer Firmware
*
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
* Copyright (c) 2016 Bob Cousins bobcousins42@googlemail.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
/**
* HAL Timers for Arduino Due and compatible (SAM3X8E)
*/
#include <stdint.h>
// ------------------------
// Defines
// ------------------------
#define FORCE_INLINE __attribute__((always_inline)) inline
typedef uint32_t hal_timer_t;
#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
#define HAL_TIMER_PRESCALER 2
#define HAL_TIMER_RATE ((F_CPU) / (HAL_TIMER_PRESCALER)) // frequency of timers peripherals
#ifndef MF_TIMER_STEP
#define MF_TIMER_STEP 2 // Timer Index for Stepper
#endif
#ifndef MF_TIMER_PULSE
#define MF_TIMER_PULSE MF_TIMER_STEP
#endif
#ifndef MF_TIMER_TEMP
#define MF_TIMER_TEMP 4 // Timer Index for Temperature
#endif
#ifndef MF_TIMER_TONE
#define MF_TIMER_TONE 6 // index of timer to use for beeper tones
#endif
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
#define STEPPER_TIMER_TICKS_PER_US ((STEPPER_TIMER_RATE) / 1000000) // stepper timer ticks per µs
#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
#define PULSE_TIMER_RATE STEPPER_TIMER_RATE // frequency of pulse timer
#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_STEP)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_STEP)
#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(MF_TIMER_STEP)
#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(MF_TIMER_TEMP)
#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(MF_TIMER_TEMP)
#ifndef HAL_STEP_TIMER_ISR
#define HAL_STEP_TIMER_ISR() void TC2_Handler()
#endif
#ifndef HAL_TEMP_TIMER_ISR
#define HAL_TEMP_TIMER_ISR() void TC4_Handler()
#endif
#ifndef HAL_TONE_TIMER_ISR
#define HAL_TONE_TIMER_ISR() void TC6_Handler()
#endif
// ------------------------
// Types
// ------------------------
typedef struct {
Tc *pTimerRegs;
uint16_t channel;
IRQn_Type IRQ_Id;
uint8_t priority;
} tTimerConfig;
// ------------------------
// Public Variables
// ------------------------
extern const tTimerConfig timer_config[];
// ------------------------
// Public functions
// ------------------------
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC = compare;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_RC;
}
FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
return pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_CV;
}
void HAL_timer_enable_interrupt(const uint8_t timer_num);
void HAL_timer_disable_interrupt(const uint8_t timer_num);
bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
const tTimerConfig * const pConfig = &timer_config[timer_num];
// Reading the status register clears the interrupt flag
pConfig->pTimerRegs->TC_CHANNEL[pConfig->channel].TC_SR;
}
#define HAL_timer_isr_epilogue(T) NOOP

View File

@ -0,0 +1,19 @@
#
# Set upload_command
#
# Windows: bossac.exe
# Other: leave unchanged
#
import pioutil
if pioutil.is_pio_build():
import platform
current_OS = platform.system()
if current_OS == 'Windows':
Import("env")
# Use bossac.exe on Windows
env.Replace(
UPLOADCMD="bossac --info --unlock --write --verify --reset --erase -U false --boot $SOURCE"
)

View File

@ -0,0 +1,97 @@
/**
* \file
*
* \brief Arduino Due/X Board Definition.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
#pragma once
/**
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
/**
* \page arduino_due_x_opfreq "Arduino Due/X - Operating frequencies"
* This page lists several definition related to the board operating frequency
*
* \section Definitions
* - \ref BOARD_FREQ_*
* - \ref BOARD_MCK
*/
/*! Board oscillator settings */
#define BOARD_FREQ_SLCK_XTAL (32768U)
#define BOARD_FREQ_SLCK_BYPASS (32768U)
#define BOARD_FREQ_MAINCK_XTAL (12000000U)
#define BOARD_FREQ_MAINCK_BYPASS (12000000U)
/*! Master clock frequency */
#define BOARD_MCK CHIP_FREQ_CPU_MAX
#define BOARD_NO_32K_XTAL
/** board main clock xtal startup time */
#define BOARD_OSC_STARTUP_US 15625
/* ------------------------------------------------------------------------ */
/**
* \page arduino_due_x_board_info "Arduino Due/X - Board information"
* This page lists several definition related to the board description.
*
*/
/* ------------------------------------------------------------------------ */
/* USB */
/* ------------------------------------------------------------------------ */
/*! USB OTG VBus On/Off: Bus Power Control Port. */
#define PIN_UOTGHS_VBOF { PIO_PB10, PIOB, ID_PIOB, PIO_PERIPH_A, PIO_PULLUP }
/*! USB OTG Identification: Mini Connector Identification Port. */
#define PIN_UOTGHS_ID { PIO_PB11, PIOB, ID_PIOB, PIO_PERIPH_A, PIO_PULLUP }
/*! Multiplexed pin used for USB_ID: */
#define USB_ID PIO_PB11_IDX
#define USB_ID_GPIO (PIO_PB11_IDX)
#define USB_ID_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
/*! Multiplexed pin used for USB_VBOF: */
#define USB_VBOF PIO_PB10_IDX
#define USB_VBOF_GPIO (PIO_PB10_IDX)
#define USB_VBOF_FLAGS (PIO_PERIPH_A | PIO_DEFAULT)
/*! Active level of the USB_VBOF output pin. */
#define USB_VBOF_ACTIVE_STATE LOW
/* ------------------------------------------------------------------------ */

1150
src/HAL/DUE/usb/compiler.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
/**
* \file
*
* \brief Memory access control configuration file.
*
* Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _CONF_ACCESS_H_
#define _CONF_ACCESS_H_
#include "compiler.h"
#include "../../../inc/MarlinConfigPre.h"
/*! \name Activation of Logical Unit Numbers
*/
//! @{
#define LUN_0 ENABLE //!< SD/MMC Card over MCI Slot 0.
#define LUN_1 DISABLE
#define LUN_2 DISABLE
#define LUN_3 DISABLE
#define LUN_4 DISABLE
#define LUN_5 DISABLE
#define LUN_6 DISABLE
#define LUN_7 DISABLE
#define LUN_USB DISABLE
//! @}
/*! \name LUN 0 Definitions
*/
//! @{
#define SD_MMC_SPI_MEM LUN_0
#define LUN_ID_SD_MMC_SPI_MEM LUN_ID_0
#define LUN_0_INCLUDE "sd_mmc_spi_mem.h"
#define Lun_0_test_unit_ready sd_mmc_spi_test_unit_ready
#define Lun_0_read_capacity sd_mmc_spi_read_capacity
#define Lun_0_unload sd_mmc_spi_unload
#define Lun_0_wr_protect sd_mmc_spi_wr_protect
#define Lun_0_removal sd_mmc_spi_removal
#define Lun_0_usb_read_10 sd_mmc_spi_usb_read_10
#define Lun_0_usb_write_10 sd_mmc_spi_usb_write_10
#define LUN_0_NAME "\"SD/MMC Card\""
//! @}
/*! \name Actions Associated with Memory Accesses
*
* Write here the action to associate with each memory access.
*
* \warning Be careful not to waste time in order not to disturb the functions.
*/
//! @{
#define memory_start_read_action(nb_sectors)
#define memory_stop_read_action()
#define memory_start_write_action(nb_sectors)
#define memory_stop_write_action()
//! @}
/*! \name Activation of Interface Features
*/
//! @{
#define ACCESS_USB true //!< MEM <-> USB interface.
#define ACCESS_MEM_TO_RAM false //!< MEM <-> RAM interface.
#define ACCESS_STREAM false //!< Streaming MEM <-> MEM interface.
#define ACCESS_STREAM_RECORD false //!< Streaming MEM <-> MEM interface in record mode.
#define ACCESS_MEM_TO_MEM false //!< MEM <-> MEM interface.
#define ACCESS_CODEC false //!< Codec interface.
//! @}
/*! \name Specific Options for Access Control
*/
//! @{
#define GLOBAL_WR_PROTECT false //!< Management of a global write protection.
//! @}
#endif // _CONF_ACCESS_H_

View File

@ -0,0 +1,100 @@
/**
* \file
*
* \brief SAM3X clock configuration.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED
// ===== System Clock (MCK) Source Options
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_XTAL
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_SLCK_BYPASS
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_8M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_12M_RC
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_XTAL
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_BYPASS
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK
//#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_UPLLCK
// ===== System Clock (MCK) Prescaler Options (Fmck = Fsys / (SYSCLK_PRES))
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_1
#define CONFIG_SYSCLK_PRES SYSCLK_PRES_2
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_4
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_8
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_16
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_32
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_64
//#define CONFIG_SYSCLK_PRES SYSCLK_PRES_3
// ===== PLL0 (A) Options (Fpll = (Fclk * PLL_mul) / PLL_div)
// Use mul and div effective values here.
#define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL
#define CONFIG_PLL0_MUL 14
#define CONFIG_PLL0_DIV 1
// ===== UPLL (UTMI) Hardware fixed at 480MHz.
// ===== USB Clock Source Options (Fusb = FpllX / USB_div)
// Use div effective value here.
//#define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL0
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_UPLL
#define CONFIG_USBCLK_DIV 1
// ===== Target frequency (System clock)
// - XTAL frequency: 12MHz
// - System clock source: PLLA
// - System clock prescaler: 2 (divided by 2)
// - PLLA source: XTAL
// - PLLA output: XTAL * 14 / 1
// - System clock is: 12 * 14 / 1 /2 = 84MHz
// ===== Target frequency (USB Clock)
// - USB clock source: UPLL
// - USB clock divider: 1 (not divided)
// - UPLL frequency: 480MHz
// - USB clock: 480 / 1 = 480MHz
#endif /* CONF_CLOCK_H_INCLUDED */

296
src/HAL/DUE/usb/conf_usb.h Normal file
View File

@ -0,0 +1,296 @@
/**
* \file
*
* \brief USB configuration file
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _CONF_USB_H_
#define _CONF_USB_H_
#undef UNUSED /* To avoid a macro clash as macros.h already defines it */
#include "../../../inc/MarlinConfigPre.h"
#include "compiler.h"
/**
* USB Device Configuration
* @{
*/
//! Device definition (mandatory)
#define USB_DEVICE_MAJOR_VERSION 1
#define USB_DEVICE_MINOR_VERSION 0
#define USB_DEVICE_POWER 100 // Consumption on Vbus line (mA)
#define USB_DEVICE_ATTR \
(USB_CONFIG_ATTR_SELF_POWERED)
// (USB_CONFIG_ATTR_BUS_POWERED)
// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_SELF_POWERED)
// (USB_CONFIG_ATTR_REMOTE_WAKEUP|USB_CONFIG_ATTR_BUS_POWERED)
/**
* Device speeds support
* Low speed not supported by CDC and MSC
* @{
*/
//! To define a Low speed device
//#define USB_DEVICE_LOW_SPEED
//! To define a Full speed device
//#define USB_DEVICE_FULL_SPEED
//! To authorize the High speed
#ifndef USB_DEVICE_FULL_SPEED
#if (UC3A3||UC3A4)
#define USB_DEVICE_HS_SUPPORT
#elif (SAM3XA||SAM3U)
#define USB_DEVICE_HS_SUPPORT
#endif
#endif
//@}
/**
* USB Device Callbacks definitions (Optional)
* @{
*/
#define UDC_VBUS_EVENT(b_vbus_high)
#define UDC_SOF_EVENT()
#define UDC_SUSPEND_EVENT()
#define UDC_RESUME_EVENT()
#define UDC_GET_EXTRA_STRING() usb_task_extra_string()
#define USB_DEVICE_SPECIFIC_REQUEST() usb_task_other_requests()
//@}
#if ENABLED(SDSUPPORT)
/**
* USB Device low level configuration
* When only one interface is used, these configurations are defined by the class module.
* For composite device, these configuration must be defined here
* @{
*/
//! Control endpoint size
#define USB_DEVICE_EP_CTRL_SIZE 64
//! Two interfaces for this device (CDC COM + CDC DATA + MSC)
#define USB_DEVICE_NB_INTERFACE 3
//! 5 endpoints used by CDC and MSC interfaces
#if SAM3U
// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
// (6 | USB_EP_DIR_IN) // CDC TX
// (5 | USB_EP_DIR_OUT) // CDC RX
// (1 | USB_EP_DIR_IN) // MSC IN
// (2 | USB_EP_DIR_OUT) // MSC OUT
# define USB_DEVICE_MAX_EP 6
# if defined(USB_DEVICE_HS_SUPPORT)
// In HS mode, size of bulk endpoints are 512
// If CDC and MSC endpoints all uses 2 banks, DPRAM is not enough: 4 bulk
// endpoints requires 4K bytes. So reduce the number of banks of CDC bulk
// endpoints to use less DPRAM. Keep MSC setting to keep MSC performance.
# define UDD_BULK_NB_BANK(ep) ((ep == 5 || ep== 6) ? 1 : 2)
#endif
#else
// (3 | USB_EP_DIR_IN) // CDC Notify endpoint
// (4 | USB_EP_DIR_IN) // CDC TX
// (5 | USB_EP_DIR_OUT) // CDC RX
// (1 | USB_EP_DIR_IN) // MSC IN
// (2 | USB_EP_DIR_OUT) // MSC OUT
# define USB_DEVICE_MAX_EP 5
# if SAM3XA && defined(USB_DEVICE_HS_SUPPORT)
// In HS mode, size of bulk endpoints are 512
// If CDC and MSC endpoints all uses 2 banks, DPRAM is not enough: 4 bulk
// endpoints requires 4K bytes. So reduce the number of banks of CDC bulk
// endpoints to use less DPRAM. Keep MSC setting to keep MSC performance.
# define UDD_BULK_NB_BANK(ep) ((ep == 4 || ep== 5) ? 1 : 2)
# endif
#endif
#endif
//@}
//@}
/**
* USB Interface Configuration
* @{
*/
/**
* Configuration of CDC interface
* @{
*/
//! Define one USB communication ports
#define UDI_CDC_PORT_NB 1
//! Interface callback definition
#define UDI_CDC_ENABLE_EXT(port) usb_task_cdc_enable(port)
#define UDI_CDC_DISABLE_EXT(port) usb_task_cdc_disable(port)
#define UDI_CDC_RX_NOTIFY(port) usb_task_cdc_rx_notify(port)
#define UDI_CDC_TX_EMPTY_NOTIFY(port)
#define UDI_CDC_SET_CODING_EXT(port,cfg) usb_task_cdc_config(port,cfg)
#define UDI_CDC_SET_DTR_EXT(port,set) usb_task_cdc_set_dtr(port,set)
#define UDI_CDC_SET_RTS_EXT(port,set)
//! Define it when the transfer CDC Device to Host is a low rate (<512000 bauds)
//! to reduce CDC buffers size
//#define UDI_CDC_LOW_RATE
//! Default configuration of communication port
#define UDI_CDC_DEFAULT_RATE 115200
#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
#define UDI_CDC_DEFAULT_DATABITS 8
//! Enable id string of interface to add an extra USB string
#define UDI_CDC_IAD_STRING_ID 4
#if ENABLED(SDSUPPORT)
/**
* USB CDC low level configuration
* In standalone these configurations are defined by the CDC module.
* For composite device, these configuration must be defined here
* @{
*/
//! Endpoint numbers definition
#if SAM3U
# define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
# define UDI_CDC_DATA_EP_IN_0 (6 | USB_EP_DIR_IN) // TX
# define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT)// RX
#else
# define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
# define UDI_CDC_DATA_EP_IN_0 (4 | USB_EP_DIR_IN) // TX
# define UDI_CDC_DATA_EP_OUT_0 (5 | USB_EP_DIR_OUT)// RX
#endif
//! Interface numbers
#define UDI_CDC_COMM_IFACE_NUMBER_0 0
#define UDI_CDC_DATA_IFACE_NUMBER_0 1
//@}
//@}
/**
* Configuration of MSC interface
* @{
*/
//! Vendor name and Product version of MSC interface
#define UDI_MSC_GLOBAL_VENDOR_ID \
'M', 'A', 'R', 'L', 'I', 'N', '3', 'D'
#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
'1', '.', '0', '0'
//! Interface callback definition
#define UDI_MSC_ENABLE_EXT() usb_task_msc_enable()
#define UDI_MSC_DISABLE_EXT() usb_task_msc_disable()
//! Enable id string of interface to add an extra USB string
#define UDI_MSC_STRING_ID 5
/**
* USB MSC low level configuration
* In standalone these configurations are defined by the MSC module.
* For composite device, these configuration must be defined here
* @{
*/
//! Endpoint numbers definition
#define UDI_MSC_EP_IN (1 | USB_EP_DIR_IN)
#define UDI_MSC_EP_OUT (2 | USB_EP_DIR_OUT)
//! Interface number
#define UDI_MSC_IFACE_NUMBER 2
//@}
//@}
//@}
/**
* Description of Composite Device
* @{
*/
//! USB Interfaces descriptor structure
#define UDI_COMPOSITE_DESC_T \
usb_iad_desc_t udi_cdc_iad; \
udi_cdc_comm_desc_t udi_cdc_comm; \
udi_cdc_data_desc_t udi_cdc_data; \
udi_msc_desc_t udi_msc
//! USB Interfaces descriptor value for Full Speed
#define UDI_COMPOSITE_DESC_FS \
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
.udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
.udi_msc = UDI_MSC_DESC_FS
//! USB Interfaces descriptor value for High Speed
#define UDI_COMPOSITE_DESC_HS \
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
.udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
.udi_msc = UDI_MSC_DESC_HS
//! USB Interface APIs
#define UDI_COMPOSITE_API \
&udi_api_cdc_comm, \
&udi_api_cdc_data, \
&udi_api_msc
//@}
/**
* USB Device Driver Configuration
* @{
*/
//@}
//! The includes of classes and other headers must be done at the end of this file to avoid compile error
#include "udi_cdc.h"
#include "udi_msc.h"
#else
#include "udi_cdc_conf.h"
#endif
#include "usb_task.h"
#endif // _CONF_USB_H_

View File

@ -0,0 +1,647 @@
/*****************************************************************************
*
* \file
*
* \brief Abstraction layer for memory interfaces.
*
* This module contains the interfaces:
* - MEM <-> USB;
* - MEM <-> RAM;
* - MEM <-> MEM.
*
* This module may be configured and expanded to support the following features:
* - write-protected globals;
* - password-protected data;
* - specific features;
* - etc.
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
******************************************************************************/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifdef ARDUINO_ARCH_SAM
//_____ I N C L U D E S ____________________________________________________
#include "compiler.h"
#include "preprocessor.h"
#ifdef FREERTOS_USED
#include "FreeRTOS.h"
#include "semphr.h"
#endif
#include "ctrl_access.h"
//_____ D E F I N I T I O N S ______________________________________________
#ifdef FREERTOS_USED
/*! \name LUN Access Protection Macros
*/
//! @{
/*! \brief Locks accesses to LUNs.
*
* \return \c true if the access was successfully locked, else \c false.
*/
#define Ctrl_access_lock() ctrl_access_lock()
/*! \brief Unlocks accesses to LUNs.
*/
#define Ctrl_access_unlock() xSemaphoreGive(ctrl_access_semphr)
//! @}
//! Handle to the semaphore protecting accesses to LUNs.
static xSemaphoreHandle ctrl_access_semphr = NULL;
#else
/*! \name LUN Access Protection Macros
*/
//! @{
/*! \brief Locks accesses to LUNs.
*
* \return \c true if the access was successfully locked, else \c false.
*/
#define Ctrl_access_lock() true
/*! \brief Unlocks accesses to LUNs.
*/
#define Ctrl_access_unlock()
//! @}
#endif // FREERTOS_USED
#if MAX_LUN
/*! \brief Initializes an entry of the LUN descriptor table.
*
* \param lun Logical Unit Number.
*
* \return LUN descriptor table entry initializer.
*/
#if ACCESS_USB == true && ACCESS_MEM_TO_RAM == true
#define Lun_desc_entry(lun) \
{\
TPASTE3(Lun_, lun, _test_unit_ready),\
TPASTE3(Lun_, lun, _read_capacity),\
TPASTE3(Lun_, lun, _unload),\
TPASTE3(Lun_, lun, _wr_protect),\
TPASTE3(Lun_, lun, _removal),\
TPASTE3(Lun_, lun, _usb_read_10),\
TPASTE3(Lun_, lun, _usb_write_10),\
TPASTE3(Lun_, lun, _mem_2_ram),\
TPASTE3(Lun_, lun, _ram_2_mem),\
TPASTE3(LUN_, lun, _NAME)\
}
#elif ACCESS_USB == true
#define Lun_desc_entry(lun) \
{\
TPASTE3(Lun_, lun, _test_unit_ready),\
TPASTE3(Lun_, lun, _read_capacity),\
TPASTE3(Lun_, lun, _unload),\
TPASTE3(Lun_, lun, _wr_protect),\
TPASTE3(Lun_, lun, _removal),\
TPASTE3(Lun_, lun, _usb_read_10),\
TPASTE3(Lun_, lun, _usb_write_10),\
TPASTE3(LUN_, lun, _NAME)\
}
#elif ACCESS_MEM_TO_RAM == true
#define Lun_desc_entry(lun) \
{\
TPASTE3(Lun_, lun, _test_unit_ready),\
TPASTE3(Lun_, lun, _read_capacity),\
TPASTE3(Lun_, lun, _unload),\
TPASTE3(Lun_, lun, _wr_protect),\
TPASTE3(Lun_, lun, _removal),\
TPASTE3(Lun_, lun, _mem_2_ram),\
TPASTE3(Lun_, lun, _ram_2_mem),\
TPASTE3(LUN_, lun, _NAME)\
}
#else
#define Lun_desc_entry(lun) \
{\
TPASTE3(Lun_, lun, _test_unit_ready),\
TPASTE3(Lun_, lun, _read_capacity),\
TPASTE3(Lun_, lun, _unload),\
TPASTE3(Lun_, lun, _wr_protect),\
TPASTE3(Lun_, lun, _removal),\
TPASTE3(LUN_, lun, _NAME)\
}
#endif
//! LUN descriptor table.
static const struct
{
Ctrl_status (*test_unit_ready)(void);
Ctrl_status (*read_capacity)(U32 *);
bool (*unload)(bool);
bool (*wr_protect)(void);
bool (*removal)(void);
#if ACCESS_USB == true
Ctrl_status (*usb_read_10)(U32, U16);
Ctrl_status (*usb_write_10)(U32, U16);
#endif
#if ACCESS_MEM_TO_RAM == true
Ctrl_status (*mem_2_ram)(U32, void *);
Ctrl_status (*ram_2_mem)(U32, const void *);
#endif
const char *name;
} lun_desc[MAX_LUN] =
{
#if LUN_0 == ENABLE
# ifndef Lun_0_unload
# define Lun_0_unload NULL
# endif
Lun_desc_entry(0),
#endif
#if LUN_1 == ENABLE
# ifndef Lun_1_unload
# define Lun_1_unload NULL
# endif
Lun_desc_entry(1),
#endif
#if LUN_2 == ENABLE
# ifndef Lun_2_unload
# define Lun_2_unload NULL
# endif
Lun_desc_entry(2),
#endif
#if LUN_3 == ENABLE
# ifndef Lun_3_unload
# define Lun_3_unload NULL
# endif
Lun_desc_entry(3),
#endif
#if LUN_4 == ENABLE
# ifndef Lun_4_unload
# define Lun_4_unload NULL
# endif
Lun_desc_entry(4),
#endif
#if LUN_5 == ENABLE
# ifndef Lun_5_unload
# define Lun_5_unload NULL
# endif
Lun_desc_entry(5),
#endif
#if LUN_6 == ENABLE
# ifndef Lun_6_unload
# define Lun_6_unload NULL
# endif
Lun_desc_entry(6),
#endif
#if LUN_7 == ENABLE
# ifndef Lun_7_unload
# define Lun_7_unload NULL
# endif
Lun_desc_entry(7)
#endif
};
#endif
#if GLOBAL_WR_PROTECT == true
bool g_wr_protect;
#endif
/*! \name Control Interface
*/
//! @{
#ifdef FREERTOS_USED
bool ctrl_access_init(void)
{
// If the handle to the protecting semaphore is not valid,
if (!ctrl_access_semphr)
{
// try to create the semaphore.
vSemaphoreCreateBinary(ctrl_access_semphr);
// If the semaphore could not be created, there is no backup solution.
if (!ctrl_access_semphr) return false;
}
return true;
}
/*! \brief Locks accesses to LUNs.
*
* \return \c true if the access was successfully locked, else \c false.
*/
static bool ctrl_access_lock(void)
{
// If the semaphore could not be created, there is no backup solution.
if (!ctrl_access_semphr) return false;
// Wait for the semaphore.
while (!xSemaphoreTake(ctrl_access_semphr, portMAX_DELAY));
return true;
}
#endif // FREERTOS_USED
U8 get_nb_lun(void)
{
#if MEM_USB == ENABLE
# ifndef Lun_usb_get_lun
# define Lun_usb_get_lun() host_get_lun()
# endif
U8 nb_lun;
if (!Ctrl_access_lock()) return MAX_LUN;
nb_lun = MAX_LUN + Lun_usb_get_lun();
Ctrl_access_unlock();
return nb_lun;
#else
return MAX_LUN;
#endif
}
U8 get_cur_lun(void)
{
return LUN_ID_0;
}
Ctrl_status mem_test_unit_ready(U8 lun)
{
Ctrl_status status;
if (!Ctrl_access_lock()) return CTRL_FAIL;
status =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].test_unit_ready() :
#endif
#if LUN_USB == ENABLE
Lun_usb_test_unit_ready(lun - LUN_ID_USB);
#else
CTRL_FAIL;
#endif
Ctrl_access_unlock();
return status;
}
Ctrl_status mem_read_capacity(U8 lun, U32 *u32_nb_sector)
{
Ctrl_status status;
if (!Ctrl_access_lock()) return CTRL_FAIL;
status =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].read_capacity(u32_nb_sector) :
#endif
#if LUN_USB == ENABLE
Lun_usb_read_capacity(lun - LUN_ID_USB, u32_nb_sector);
#else
CTRL_FAIL;
#endif
Ctrl_access_unlock();
return status;
}
U8 mem_sector_size(U8 lun)
{
U8 sector_size;
if (!Ctrl_access_lock()) return 0;
sector_size =
#if MAX_LUN
(lun < MAX_LUN) ? 1 :
#endif
#if LUN_USB == ENABLE
Lun_usb_read_sector_size(lun - LUN_ID_USB);
#else
0;
#endif
Ctrl_access_unlock();
return sector_size;
}
bool mem_unload(U8 lun, bool unload)
{
bool unloaded;
#if !MAX_LUN || !defined(Lun_usb_unload)
UNUSED(lun);
#endif
if (!Ctrl_access_lock()) return false;
unloaded =
#if MAX_LUN
(lun < MAX_LUN) ?
(lun_desc[lun].unload ?
lun_desc[lun].unload(unload) : !unload) :
#endif
#if LUN_USB == ENABLE
# if defined(Lun_usb_unload)
Lun_usb_unload(lun - LUN_ID_USB, unload);
# else
!unload; /* Can not unload: load success, unload fail */
# endif
#else
false; /* No mem, unload/load fail */
#endif
Ctrl_access_unlock();
return unloaded;
}
bool mem_wr_protect(U8 lun)
{
bool wr_protect;
if (!Ctrl_access_lock()) return true;
wr_protect =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].wr_protect() :
#endif
#if LUN_USB == ENABLE
Lun_usb_wr_protect(lun - LUN_ID_USB);
#else
true;
#endif
Ctrl_access_unlock();
return wr_protect;
}
bool mem_removal(U8 lun)
{
bool removal;
#if MAX_LUN==0
UNUSED(lun);
#endif
if (!Ctrl_access_lock()) return true;
removal =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].removal() :
#endif
#if LUN_USB == ENABLE
Lun_usb_removal();
#else
true;
#endif
Ctrl_access_unlock();
return removal;
}
const char *mem_name(U8 lun)
{
#if MAX_LUN==0
UNUSED(lun);
#endif
return
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].name :
#endif
#if LUN_USB == ENABLE
LUN_USB_NAME;
#else
NULL;
#endif
}
//! @}
#if ACCESS_USB == true
/*! \name MEM <-> USB Interface
*/
//! @{
Ctrl_status memory_2_usb(U8 lun, U32 addr, U16 nb_sector)
{
Ctrl_status status;
if (!Ctrl_access_lock()) return CTRL_FAIL;
memory_start_read_action(nb_sector);
status =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].usb_read_10(addr, nb_sector) :
#endif
CTRL_FAIL;
memory_stop_read_action();
Ctrl_access_unlock();
return status;
}
Ctrl_status usb_2_memory(U8 lun, U32 addr, U16 nb_sector)
{
Ctrl_status status;
if (!Ctrl_access_lock()) return CTRL_FAIL;
memory_start_write_action(nb_sector);
status =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].usb_write_10(addr, nb_sector) :
#endif
CTRL_FAIL;
memory_stop_write_action();
Ctrl_access_unlock();
return status;
}
//! @}
#endif // ACCESS_USB == true
#if ACCESS_MEM_TO_RAM == true
/*! \name MEM <-> RAM Interface
*/
//! @{
Ctrl_status memory_2_ram(U8 lun, U32 addr, void *ram)
{
Ctrl_status status;
#if MAX_LUN==0
UNUSED(lun);
#endif
if (!Ctrl_access_lock()) return CTRL_FAIL;
memory_start_read_action(1);
status =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].mem_2_ram(addr, ram) :
#endif
#if LUN_USB == ENABLE
Lun_usb_mem_2_ram(addr, ram);
#else
CTRL_FAIL;
#endif
memory_stop_read_action();
Ctrl_access_unlock();
return status;
}
Ctrl_status ram_2_memory(U8 lun, U32 addr, const void *ram)
{
Ctrl_status status;
#if MAX_LUN==0
UNUSED(lun);
#endif
if (!Ctrl_access_lock()) return CTRL_FAIL;
memory_start_write_action(1);
status =
#if MAX_LUN
(lun < MAX_LUN) ? lun_desc[lun].ram_2_mem(addr, ram) :
#endif
#if LUN_USB == ENABLE
Lun_usb_ram_2_mem(addr, ram);
#else
CTRL_FAIL;
#endif
memory_stop_write_action();
Ctrl_access_unlock();
return status;
}
//! @}
#endif // ACCESS_MEM_TO_RAM == true
#if ACCESS_STREAM == true
/*! \name Streaming MEM <-> MEM Interface
*/
//! @{
#if ACCESS_MEM_TO_MEM == true
#include "fat.h"
Ctrl_status stream_mem_to_mem(U8 src_lun, U32 src_addr, U8 dest_lun, U32 dest_addr, U16 nb_sector)
{
COMPILER_ALIGNED(4)
static U8 sector_buf[FS_512B];
Ctrl_status status = CTRL_GOOD;
while (nb_sector--)
{
if ((status = memory_2_ram(src_lun, src_addr++, sector_buf)) != CTRL_GOOD) break;
if ((status = ram_2_memory(dest_lun, dest_addr++, sector_buf)) != CTRL_GOOD) break;
}
return status;
}
#endif // ACCESS_MEM_TO_MEM == true
Ctrl_status stream_state(U8 id)
{
UNUSED(id);
return CTRL_GOOD;
}
U16 stream_stop(U8 id)
{
UNUSED(id);
return 0;
}
//! @}
#endif // ACCESS_STREAM
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,402 @@
/*****************************************************************************
*
* \file
*
* \brief Abstraction layer for memory interfaces.
*
* This module contains the interfaces:
* - MEM <-> USB;
* - MEM <-> RAM;
* - MEM <-> MEM.
*
* This module may be configured and expanded to support the following features:
* - write-protected globals;
* - password-protected data;
* - specific features;
* - etc.
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
******************************************************************************/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _CTRL_ACCESS_H_
#define _CTRL_ACCESS_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* \defgroup group_common_services_storage_ctrl_access Memory Control Access
*
* Common abstraction layer for memory interfaces. It provides interfaces between:
* Memory and USB, Memory and RAM, Memory and Memory. Common API for XMEGA and UC3.
*
* \{
*/
#include "compiler.h"
#include "conf_access.h"
#ifndef SECTOR_SIZE
#define SECTOR_SIZE 512
#endif
//! Status returned by CTRL_ACCESS interfaces.
typedef enum
{
CTRL_GOOD = PASS, //!< Success, memory ready.
CTRL_FAIL = FAIL, //!< An error occurred.
CTRL_NO_PRESENT = FAIL + 1, //!< Memory unplugged.
CTRL_BUSY = FAIL + 2 //!< Memory not initialized or changed.
} Ctrl_status;
// FYI: Each Logical Unit Number (LUN) corresponds to a memory.
// Check LUN defines.
#ifndef LUN_0
#error LUN_0 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_1
#error LUN_1 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_2
#error LUN_2 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_3
#error LUN_3 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_4
#error LUN_4 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_5
#error LUN_5 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_6
#error LUN_6 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_7
#error LUN_7 must be defined as ENABLE or DISABLE in conf_access.h
#endif
#ifndef LUN_USB
#error LUN_USB must be defined as ENABLE or DISABLE in conf_access.h
#endif
/*! \name LUN IDs
*/
//! @{
#define LUN_ID_0 (0) //!< First static LUN.
#define LUN_ID_1 (LUN_ID_0 + LUN_0)
#define LUN_ID_2 (LUN_ID_1 + LUN_1)
#define LUN_ID_3 (LUN_ID_2 + LUN_2)
#define LUN_ID_4 (LUN_ID_3 + LUN_3)
#define LUN_ID_5 (LUN_ID_4 + LUN_4)
#define LUN_ID_6 (LUN_ID_5 + LUN_5)
#define LUN_ID_7 (LUN_ID_6 + LUN_6)
#define MAX_LUN (LUN_ID_7 + LUN_7) //!< Number of static LUNs.
#define LUN_ID_USB (MAX_LUN) //!< First dynamic LUN (USB host mass storage).
//! @}
// Include LUN header files.
#if LUN_0 == ENABLE
#include LUN_0_INCLUDE
#endif
#if LUN_1 == ENABLE
#include LUN_1_INCLUDE
#endif
#if LUN_2 == ENABLE
#include LUN_2_INCLUDE
#endif
#if LUN_3 == ENABLE
#include LUN_3_INCLUDE
#endif
#if LUN_4 == ENABLE
#include LUN_4_INCLUDE
#endif
#if LUN_5 == ENABLE
#include LUN_5_INCLUDE
#endif
#if LUN_6 == ENABLE
#include LUN_6_INCLUDE
#endif
#if LUN_7 == ENABLE
#include LUN_7_INCLUDE
#endif
#if LUN_USB == ENABLE
#include LUN_USB_INCLUDE
#endif
// Check the configuration of write protection in conf_access.h.
#ifndef GLOBAL_WR_PROTECT
#error GLOBAL_WR_PROTECT must be defined as true or false in conf_access.h
#endif
#if GLOBAL_WR_PROTECT == true
//! Write protect.
extern bool g_wr_protect;
#endif
/*! \name Control Interface
*/
//! @{
#ifdef FREERTOS_USED
/*! \brief Initializes the LUN access locker.
*
* \return \c true if the locker was successfully initialized, else \c false.
*/
extern bool ctrl_access_init(void);
#endif // FREERTOS_USED
/*! \brief Returns the number of LUNs.
*
* \return Number of LUNs in the system.
*/
extern U8 get_nb_lun(void);
/*! \brief Returns the current LUN.
*
* \return Current LUN.
*
* \todo Implement.
*/
extern U8 get_cur_lun(void);
/*! \brief Tests the memory state and initializes the memory if required.
*
* The TEST UNIT READY SCSI primary command allows an application client to poll
* a LUN until it is ready without having to allocate memory for returned data.
*
* This command may be used to check the media status of LUNs with removable
* media.
*
* \param lun Logical Unit Number.
*
* \return Status.
*/
extern Ctrl_status mem_test_unit_ready(U8 lun);
/*! \brief Returns the address of the last valid sector (512 bytes) in the
* memory.
*
* \param lun Logical Unit Number.
* \param u32_nb_sector Pointer to the address of the last valid sector.
*
* \return Status.
*/
extern Ctrl_status mem_read_capacity(U8 lun, U32 *u32_nb_sector);
/*! \brief Returns the size of the physical sector.
*
* \param lun Logical Unit Number.
*
* \return Sector size (unit: 512 bytes).
*/
extern U8 mem_sector_size(U8 lun);
/*! \brief Unload/load the medium.
*
* \param lun Logical Unit Number.
* \param unload \c true to unload the medium, \c false to load the medium.
*
* \return \c true if unload/load success, else \c false.
*/
extern bool mem_unload(U8 lun, bool unload);
/*! \brief Returns the write-protection state of the memory.
*
* \param lun Logical Unit Number.
*
* \return \c true if the memory is write-protected, else \c false.
*
* \note Only used by removable memories with hardware-specific write
* protection.
*/
extern bool mem_wr_protect(U8 lun);
/*! \brief Tells whether the memory is removable.
*
* \param lun Logical Unit Number.
*
* \return \c true if the memory is removable, else \c false.
*/
extern bool mem_removal(U8 lun);
/*! \brief Returns a pointer to the LUN name.
*
* \param lun Logical Unit Number.
*
* \return Pointer to the LUN name string.
*/
extern const char *mem_name(U8 lun);
//! @}
#if ACCESS_USB == true
/*! \name MEM <-> USB Interface
*/
//! @{
/*! \brief Transfers data from the memory to USB.
*
* \param lun Logical Unit Number.
* \param addr Address of first memory sector to read.
* \param nb_sector Number of sectors to transfer.
*
* \return Status.
*/
extern Ctrl_status memory_2_usb(U8 lun, U32 addr, U16 nb_sector);
/*! \brief Transfers data from USB to the memory.
*
* \param lun Logical Unit Number.
* \param addr Address of first memory sector to write.
* \param nb_sector Number of sectors to transfer.
*
* \return Status.
*/
extern Ctrl_status usb_2_memory(U8 lun, U32 addr, U16 nb_sector);
//! @}
#endif // ACCESS_USB == true
#if ACCESS_MEM_TO_RAM == true
/*! \name MEM <-> RAM Interface
*/
//! @{
/*! \brief Copies 1 data sector from the memory to RAM.
*
* \param lun Logical Unit Number.
* \param addr Address of first memory sector to read.
* \param ram Pointer to RAM buffer to write.
*
* \return Status.
*/
extern Ctrl_status memory_2_ram(U8 lun, U32 addr, void *ram);
/*! \brief Copies 1 data sector from RAM to the memory.
*
* \param lun Logical Unit Number.
* \param addr Address of first memory sector to write.
* \param ram Pointer to RAM buffer to read.
*
* \return Status.
*/
extern Ctrl_status ram_2_memory(U8 lun, U32 addr, const void *ram);
//! @}
#endif // ACCESS_MEM_TO_RAM == true
#if ACCESS_STREAM == true
/*! \name Streaming MEM <-> MEM Interface
*/
//! @{
//! Erroneous streaming data transfer ID.
#define ID_STREAM_ERR 0xFF
#if ACCESS_MEM_TO_MEM == true
/*! \brief Copies data from one memory to another.
*
* \param src_lun Source Logical Unit Number.
* \param src_addr Source address of first memory sector to read.
* \param dest_lun Destination Logical Unit Number.
* \param dest_addr Destination address of first memory sector to write.
* \param nb_sector Number of sectors to copy.
*
* \return Status.
*/
extern Ctrl_status stream_mem_to_mem(U8 src_lun, U32 src_addr, U8 dest_lun, U32 dest_addr, U16 nb_sector);
#endif // ACCESS_MEM_TO_MEM == true
/*! \brief Returns the state of a streaming data transfer.
*
* \param id Transfer ID.
*
* \return Status.
*
* \todo Implement.
*/
extern Ctrl_status stream_state(U8 id);
/*! \brief Stops a streaming data transfer.
*
* \param id Transfer ID.
*
* \return Number of remaining sectors.
*
* \todo Implement.
*/
extern U16 stream_stop(U8 id);
//! @}
#endif // ACCESS_STREAM == true
/**
* \}
*/
#ifdef __cplusplus
}
#endif
#endif // _CTRL_ACCESS_H_

278
src/HAL/DUE/usb/genclk.h Normal file
View File

@ -0,0 +1,278 @@
/**
* \file
*
* \brief Chip-specific generic clock management.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CHIP_GENCLK_H_INCLUDED
#define CHIP_GENCLK_H_INCLUDED
#include <osc.h>
#include <pll.h>
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \weakgroup genclk_group
* @{
*/
//! \name Programmable Clock Identifiers (PCK)
//@{
#define GENCLK_PCK_0 0 //!< PCK0 ID
#define GENCLK_PCK_1 1 //!< PCK1 ID
#define GENCLK_PCK_2 2 //!< PCK2 ID
//@}
//! \name Programmable Clock Sources (PCK)
//@{
enum genclk_source {
GENCLK_PCK_SRC_SLCK_RC = 0, //!< Internal 32kHz RC oscillator as PCK source clock
GENCLK_PCK_SRC_SLCK_XTAL = 1, //!< External 32kHz crystal oscillator as PCK source clock
GENCLK_PCK_SRC_SLCK_BYPASS = 2, //!< External 32kHz bypass oscillator as PCK source clock
GENCLK_PCK_SRC_MAINCK_4M_RC = 3, //!< Internal 4MHz RC oscillator as PCK source clock
GENCLK_PCK_SRC_MAINCK_8M_RC = 4, //!< Internal 8MHz RC oscillator as PCK source clock
GENCLK_PCK_SRC_MAINCK_12M_RC = 5, //!< Internal 12MHz RC oscillator as PCK source clock
GENCLK_PCK_SRC_MAINCK_XTAL = 6, //!< External crystal oscillator as PCK source clock
GENCLK_PCK_SRC_MAINCK_BYPASS = 7, //!< External bypass oscillator as PCK source clock
GENCLK_PCK_SRC_PLLACK = 8, //!< Use PLLACK as PCK source clock
GENCLK_PCK_SRC_PLLBCK = 9, //!< Use PLLBCK as PCK source clock
GENCLK_PCK_SRC_MCK = 10, //!< Use Master Clk as PCK source clock
};
//@}
//! \name Programmable Clock Prescalers (PCK)
//@{
enum genclk_divider {
GENCLK_PCK_PRES_1 = PMC_PCK_PRES_CLK_1, //!< Set PCK clock prescaler to 1
GENCLK_PCK_PRES_2 = PMC_PCK_PRES_CLK_2, //!< Set PCK clock prescaler to 2
GENCLK_PCK_PRES_4 = PMC_PCK_PRES_CLK_4, //!< Set PCK clock prescaler to 4
GENCLK_PCK_PRES_8 = PMC_PCK_PRES_CLK_8, //!< Set PCK clock prescaler to 8
GENCLK_PCK_PRES_16 = PMC_PCK_PRES_CLK_16, //!< Set PCK clock prescaler to 16
GENCLK_PCK_PRES_32 = PMC_PCK_PRES_CLK_32, //!< Set PCK clock prescaler to 32
GENCLK_PCK_PRES_64 = PMC_PCK_PRES_CLK_64, //!< Set PCK clock prescaler to 64
};
//@}
struct genclk_config {
uint32_t ctrl;
};
static inline void genclk_config_defaults(struct genclk_config *p_cfg,
uint32_t ul_id)
{
ul_id = ul_id;
p_cfg->ctrl = 0;
}
static inline void genclk_config_read(struct genclk_config *p_cfg,
uint32_t ul_id)
{
p_cfg->ctrl = PMC->PMC_PCK[ul_id];
}
static inline void genclk_config_write(const struct genclk_config *p_cfg,
uint32_t ul_id)
{
PMC->PMC_PCK[ul_id] = p_cfg->ctrl;
}
//! \name Programmable Clock Source and Prescaler configuration
//@{
static inline void genclk_config_set_source(struct genclk_config *p_cfg,
enum genclk_source e_src)
{
p_cfg->ctrl &= (~PMC_PCK_CSS_Msk);
switch (e_src) {
case GENCLK_PCK_SRC_SLCK_RC:
case GENCLK_PCK_SRC_SLCK_XTAL:
case GENCLK_PCK_SRC_SLCK_BYPASS:
p_cfg->ctrl |= (PMC_PCK_CSS_SLOW_CLK);
break;
case GENCLK_PCK_SRC_MAINCK_4M_RC:
case GENCLK_PCK_SRC_MAINCK_8M_RC:
case GENCLK_PCK_SRC_MAINCK_12M_RC:
case GENCLK_PCK_SRC_MAINCK_XTAL:
case GENCLK_PCK_SRC_MAINCK_BYPASS:
p_cfg->ctrl |= (PMC_PCK_CSS_MAIN_CLK);
break;
case GENCLK_PCK_SRC_PLLACK:
p_cfg->ctrl |= (PMC_PCK_CSS_PLLA_CLK);
break;
case GENCLK_PCK_SRC_PLLBCK:
p_cfg->ctrl |= (PMC_PCK_CSS_UPLL_CLK);
break;
case GENCLK_PCK_SRC_MCK:
p_cfg->ctrl |= (PMC_PCK_CSS_MCK);
break;
}
}
static inline void genclk_config_set_divider(struct genclk_config *p_cfg,
uint32_t e_divider)
{
p_cfg->ctrl &= ~PMC_PCK_PRES_Msk;
p_cfg->ctrl |= e_divider;
}
//@}
static inline void genclk_enable(const struct genclk_config *p_cfg,
uint32_t ul_id)
{
PMC->PMC_PCK[ul_id] = p_cfg->ctrl;
pmc_enable_pck(ul_id);
}
static inline void genclk_disable(uint32_t ul_id)
{
pmc_disable_pck(ul_id);
}
static inline void genclk_enable_source(enum genclk_source e_src)
{
switch (e_src) {
case GENCLK_PCK_SRC_SLCK_RC:
if (!osc_is_ready(OSC_SLCK_32K_RC)) {
osc_enable(OSC_SLCK_32K_RC);
osc_wait_ready(OSC_SLCK_32K_RC);
}
break;
case GENCLK_PCK_SRC_SLCK_XTAL:
if (!osc_is_ready(OSC_SLCK_32K_XTAL)) {
osc_enable(OSC_SLCK_32K_XTAL);
osc_wait_ready(OSC_SLCK_32K_XTAL);
}
break;
case GENCLK_PCK_SRC_SLCK_BYPASS:
if (!osc_is_ready(OSC_SLCK_32K_BYPASS)) {
osc_enable(OSC_SLCK_32K_BYPASS);
osc_wait_ready(OSC_SLCK_32K_BYPASS);
}
break;
case GENCLK_PCK_SRC_MAINCK_4M_RC:
if (!osc_is_ready(OSC_MAINCK_4M_RC)) {
osc_enable(OSC_MAINCK_4M_RC);
osc_wait_ready(OSC_MAINCK_4M_RC);
}
break;
case GENCLK_PCK_SRC_MAINCK_8M_RC:
if (!osc_is_ready(OSC_MAINCK_8M_RC)) {
osc_enable(OSC_MAINCK_8M_RC);
osc_wait_ready(OSC_MAINCK_8M_RC);
}
break;
case GENCLK_PCK_SRC_MAINCK_12M_RC:
if (!osc_is_ready(OSC_MAINCK_12M_RC)) {
osc_enable(OSC_MAINCK_12M_RC);
osc_wait_ready(OSC_MAINCK_12M_RC);
}
break;
case GENCLK_PCK_SRC_MAINCK_XTAL:
if (!osc_is_ready(OSC_MAINCK_XTAL)) {
osc_enable(OSC_MAINCK_XTAL);
osc_wait_ready(OSC_MAINCK_XTAL);
}
break;
case GENCLK_PCK_SRC_MAINCK_BYPASS:
if (!osc_is_ready(OSC_MAINCK_BYPASS)) {
osc_enable(OSC_MAINCK_BYPASS);
osc_wait_ready(OSC_MAINCK_BYPASS);
}
break;
#ifdef CONFIG_PLL0_SOURCE
case GENCLK_PCK_SRC_PLLACK:
pll_enable_config_defaults(0);
break;
#endif
#ifdef CONFIG_PLL1_SOURCE
case GENCLK_PCK_SRC_PLLBCK:
pll_enable_config_defaults(1);
break;
#endif
case GENCLK_PCK_SRC_MCK:
break;
default:
Assert(false);
break;
}
}
//! @}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* CHIP_GENCLK_H_INCLUDED */

339
src/HAL/DUE/usb/mrepeat.h Normal file
View File

@ -0,0 +1,339 @@
/**
* \file
*
* \brief Preprocessor macro repeating utils.
*
* Copyright (c) 2010-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _MREPEAT_H_
#define _MREPEAT_H_
/**
* \defgroup group_sam_utils_mrepeat Preprocessor - Macro Repeat
*
* \ingroup group_sam_utils
*
* \{
*/
#include "preprocessor.h"
//! Maximal number of repetitions supported by MREPEAT.
#define MREPEAT_LIMIT 256
/*! \brief Macro repeat.
*
* This macro represents a horizontal repetition construct.
*
* \param count The number of repetitious calls to macro. Valid values range from 0 to MREPEAT_LIMIT.
* \param macro A binary operation of the form macro(n, data). This macro is expanded by MREPEAT with
* the current repetition number and the auxiliary data argument.
* \param data Auxiliary data passed to macro.
*
* \return <tt>macro(0, data) macro(1, data) ... macro(count - 1, data)</tt>
*/
#define MREPEAT(count, macro, data) TPASTE2(MREPEAT, count)(macro, data)
#define MREPEAT0( macro, data)
#define MREPEAT1( macro, data) MREPEAT0( macro, data) macro( 0, data)
#define MREPEAT2( macro, data) MREPEAT1( macro, data) macro( 1, data)
#define MREPEAT3( macro, data) MREPEAT2( macro, data) macro( 2, data)
#define MREPEAT4( macro, data) MREPEAT3( macro, data) macro( 3, data)
#define MREPEAT5( macro, data) MREPEAT4( macro, data) macro( 4, data)
#define MREPEAT6( macro, data) MREPEAT5( macro, data) macro( 5, data)
#define MREPEAT7( macro, data) MREPEAT6( macro, data) macro( 6, data)
#define MREPEAT8( macro, data) MREPEAT7( macro, data) macro( 7, data)
#define MREPEAT9( macro, data) MREPEAT8( macro, data) macro( 8, data)
#define MREPEAT10( macro, data) MREPEAT9( macro, data) macro( 9, data)
#define MREPEAT11( macro, data) MREPEAT10( macro, data) macro( 10, data)
#define MREPEAT12( macro, data) MREPEAT11( macro, data) macro( 11, data)
#define MREPEAT13( macro, data) MREPEAT12( macro, data) macro( 12, data)
#define MREPEAT14( macro, data) MREPEAT13( macro, data) macro( 13, data)
#define MREPEAT15( macro, data) MREPEAT14( macro, data) macro( 14, data)
#define MREPEAT16( macro, data) MREPEAT15( macro, data) macro( 15, data)
#define MREPEAT17( macro, data) MREPEAT16( macro, data) macro( 16, data)
#define MREPEAT18( macro, data) MREPEAT17( macro, data) macro( 17, data)
#define MREPEAT19( macro, data) MREPEAT18( macro, data) macro( 18, data)
#define MREPEAT20( macro, data) MREPEAT19( macro, data) macro( 19, data)
#define MREPEAT21( macro, data) MREPEAT20( macro, data) macro( 20, data)
#define MREPEAT22( macro, data) MREPEAT21( macro, data) macro( 21, data)
#define MREPEAT23( macro, data) MREPEAT22( macro, data) macro( 22, data)
#define MREPEAT24( macro, data) MREPEAT23( macro, data) macro( 23, data)
#define MREPEAT25( macro, data) MREPEAT24( macro, data) macro( 24, data)
#define MREPEAT26( macro, data) MREPEAT25( macro, data) macro( 25, data)
#define MREPEAT27( macro, data) MREPEAT26( macro, data) macro( 26, data)
#define MREPEAT28( macro, data) MREPEAT27( macro, data) macro( 27, data)
#define MREPEAT29( macro, data) MREPEAT28( macro, data) macro( 28, data)
#define MREPEAT30( macro, data) MREPEAT29( macro, data) macro( 29, data)
#define MREPEAT31( macro, data) MREPEAT30( macro, data) macro( 30, data)
#define MREPEAT32( macro, data) MREPEAT31( macro, data) macro( 31, data)
#define MREPEAT33( macro, data) MREPEAT32( macro, data) macro( 32, data)
#define MREPEAT34( macro, data) MREPEAT33( macro, data) macro( 33, data)
#define MREPEAT35( macro, data) MREPEAT34( macro, data) macro( 34, data)
#define MREPEAT36( macro, data) MREPEAT35( macro, data) macro( 35, data)
#define MREPEAT37( macro, data) MREPEAT36( macro, data) macro( 36, data)
#define MREPEAT38( macro, data) MREPEAT37( macro, data) macro( 37, data)
#define MREPEAT39( macro, data) MREPEAT38( macro, data) macro( 38, data)
#define MREPEAT40( macro, data) MREPEAT39( macro, data) macro( 39, data)
#define MREPEAT41( macro, data) MREPEAT40( macro, data) macro( 40, data)
#define MREPEAT42( macro, data) MREPEAT41( macro, data) macro( 41, data)
#define MREPEAT43( macro, data) MREPEAT42( macro, data) macro( 42, data)
#define MREPEAT44( macro, data) MREPEAT43( macro, data) macro( 43, data)
#define MREPEAT45( macro, data) MREPEAT44( macro, data) macro( 44, data)
#define MREPEAT46( macro, data) MREPEAT45( macro, data) macro( 45, data)
#define MREPEAT47( macro, data) MREPEAT46( macro, data) macro( 46, data)
#define MREPEAT48( macro, data) MREPEAT47( macro, data) macro( 47, data)
#define MREPEAT49( macro, data) MREPEAT48( macro, data) macro( 48, data)
#define MREPEAT50( macro, data) MREPEAT49( macro, data) macro( 49, data)
#define MREPEAT51( macro, data) MREPEAT50( macro, data) macro( 50, data)
#define MREPEAT52( macro, data) MREPEAT51( macro, data) macro( 51, data)
#define MREPEAT53( macro, data) MREPEAT52( macro, data) macro( 52, data)
#define MREPEAT54( macro, data) MREPEAT53( macro, data) macro( 53, data)
#define MREPEAT55( macro, data) MREPEAT54( macro, data) macro( 54, data)
#define MREPEAT56( macro, data) MREPEAT55( macro, data) macro( 55, data)
#define MREPEAT57( macro, data) MREPEAT56( macro, data) macro( 56, data)
#define MREPEAT58( macro, data) MREPEAT57( macro, data) macro( 57, data)
#define MREPEAT59( macro, data) MREPEAT58( macro, data) macro( 58, data)
#define MREPEAT60( macro, data) MREPEAT59( macro, data) macro( 59, data)
#define MREPEAT61( macro, data) MREPEAT60( macro, data) macro( 60, data)
#define MREPEAT62( macro, data) MREPEAT61( macro, data) macro( 61, data)
#define MREPEAT63( macro, data) MREPEAT62( macro, data) macro( 62, data)
#define MREPEAT64( macro, data) MREPEAT63( macro, data) macro( 63, data)
#define MREPEAT65( macro, data) MREPEAT64( macro, data) macro( 64, data)
#define MREPEAT66( macro, data) MREPEAT65( macro, data) macro( 65, data)
#define MREPEAT67( macro, data) MREPEAT66( macro, data) macro( 66, data)
#define MREPEAT68( macro, data) MREPEAT67( macro, data) macro( 67, data)
#define MREPEAT69( macro, data) MREPEAT68( macro, data) macro( 68, data)
#define MREPEAT70( macro, data) MREPEAT69( macro, data) macro( 69, data)
#define MREPEAT71( macro, data) MREPEAT70( macro, data) macro( 70, data)
#define MREPEAT72( macro, data) MREPEAT71( macro, data) macro( 71, data)
#define MREPEAT73( macro, data) MREPEAT72( macro, data) macro( 72, data)
#define MREPEAT74( macro, data) MREPEAT73( macro, data) macro( 73, data)
#define MREPEAT75( macro, data) MREPEAT74( macro, data) macro( 74, data)
#define MREPEAT76( macro, data) MREPEAT75( macro, data) macro( 75, data)
#define MREPEAT77( macro, data) MREPEAT76( macro, data) macro( 76, data)
#define MREPEAT78( macro, data) MREPEAT77( macro, data) macro( 77, data)
#define MREPEAT79( macro, data) MREPEAT78( macro, data) macro( 78, data)
#define MREPEAT80( macro, data) MREPEAT79( macro, data) macro( 79, data)
#define MREPEAT81( macro, data) MREPEAT80( macro, data) macro( 80, data)
#define MREPEAT82( macro, data) MREPEAT81( macro, data) macro( 81, data)
#define MREPEAT83( macro, data) MREPEAT82( macro, data) macro( 82, data)
#define MREPEAT84( macro, data) MREPEAT83( macro, data) macro( 83, data)
#define MREPEAT85( macro, data) MREPEAT84( macro, data) macro( 84, data)
#define MREPEAT86( macro, data) MREPEAT85( macro, data) macro( 85, data)
#define MREPEAT87( macro, data) MREPEAT86( macro, data) macro( 86, data)
#define MREPEAT88( macro, data) MREPEAT87( macro, data) macro( 87, data)
#define MREPEAT89( macro, data) MREPEAT88( macro, data) macro( 88, data)
#define MREPEAT90( macro, data) MREPEAT89( macro, data) macro( 89, data)
#define MREPEAT91( macro, data) MREPEAT90( macro, data) macro( 90, data)
#define MREPEAT92( macro, data) MREPEAT91( macro, data) macro( 91, data)
#define MREPEAT93( macro, data) MREPEAT92( macro, data) macro( 92, data)
#define MREPEAT94( macro, data) MREPEAT93( macro, data) macro( 93, data)
#define MREPEAT95( macro, data) MREPEAT94( macro, data) macro( 94, data)
#define MREPEAT96( macro, data) MREPEAT95( macro, data) macro( 95, data)
#define MREPEAT97( macro, data) MREPEAT96( macro, data) macro( 96, data)
#define MREPEAT98( macro, data) MREPEAT97( macro, data) macro( 97, data)
#define MREPEAT99( macro, data) MREPEAT98( macro, data) macro( 98, data)
#define MREPEAT100(macro, data) MREPEAT99( macro, data) macro( 99, data)
#define MREPEAT101(macro, data) MREPEAT100(macro, data) macro(100, data)
#define MREPEAT102(macro, data) MREPEAT101(macro, data) macro(101, data)
#define MREPEAT103(macro, data) MREPEAT102(macro, data) macro(102, data)
#define MREPEAT104(macro, data) MREPEAT103(macro, data) macro(103, data)
#define MREPEAT105(macro, data) MREPEAT104(macro, data) macro(104, data)
#define MREPEAT106(macro, data) MREPEAT105(macro, data) macro(105, data)
#define MREPEAT107(macro, data) MREPEAT106(macro, data) macro(106, data)
#define MREPEAT108(macro, data) MREPEAT107(macro, data) macro(107, data)
#define MREPEAT109(macro, data) MREPEAT108(macro, data) macro(108, data)
#define MREPEAT110(macro, data) MREPEAT109(macro, data) macro(109, data)
#define MREPEAT111(macro, data) MREPEAT110(macro, data) macro(110, data)
#define MREPEAT112(macro, data) MREPEAT111(macro, data) macro(111, data)
#define MREPEAT113(macro, data) MREPEAT112(macro, data) macro(112, data)
#define MREPEAT114(macro, data) MREPEAT113(macro, data) macro(113, data)
#define MREPEAT115(macro, data) MREPEAT114(macro, data) macro(114, data)
#define MREPEAT116(macro, data) MREPEAT115(macro, data) macro(115, data)
#define MREPEAT117(macro, data) MREPEAT116(macro, data) macro(116, data)
#define MREPEAT118(macro, data) MREPEAT117(macro, data) macro(117, data)
#define MREPEAT119(macro, data) MREPEAT118(macro, data) macro(118, data)
#define MREPEAT120(macro, data) MREPEAT119(macro, data) macro(119, data)
#define MREPEAT121(macro, data) MREPEAT120(macro, data) macro(120, data)
#define MREPEAT122(macro, data) MREPEAT121(macro, data) macro(121, data)
#define MREPEAT123(macro, data) MREPEAT122(macro, data) macro(122, data)
#define MREPEAT124(macro, data) MREPEAT123(macro, data) macro(123, data)
#define MREPEAT125(macro, data) MREPEAT124(macro, data) macro(124, data)
#define MREPEAT126(macro, data) MREPEAT125(macro, data) macro(125, data)
#define MREPEAT127(macro, data) MREPEAT126(macro, data) macro(126, data)
#define MREPEAT128(macro, data) MREPEAT127(macro, data) macro(127, data)
#define MREPEAT129(macro, data) MREPEAT128(macro, data) macro(128, data)
#define MREPEAT130(macro, data) MREPEAT129(macro, data) macro(129, data)
#define MREPEAT131(macro, data) MREPEAT130(macro, data) macro(130, data)
#define MREPEAT132(macro, data) MREPEAT131(macro, data) macro(131, data)
#define MREPEAT133(macro, data) MREPEAT132(macro, data) macro(132, data)
#define MREPEAT134(macro, data) MREPEAT133(macro, data) macro(133, data)
#define MREPEAT135(macro, data) MREPEAT134(macro, data) macro(134, data)
#define MREPEAT136(macro, data) MREPEAT135(macro, data) macro(135, data)
#define MREPEAT137(macro, data) MREPEAT136(macro, data) macro(136, data)
#define MREPEAT138(macro, data) MREPEAT137(macro, data) macro(137, data)
#define MREPEAT139(macro, data) MREPEAT138(macro, data) macro(138, data)
#define MREPEAT140(macro, data) MREPEAT139(macro, data) macro(139, data)
#define MREPEAT141(macro, data) MREPEAT140(macro, data) macro(140, data)
#define MREPEAT142(macro, data) MREPEAT141(macro, data) macro(141, data)
#define MREPEAT143(macro, data) MREPEAT142(macro, data) macro(142, data)
#define MREPEAT144(macro, data) MREPEAT143(macro, data) macro(143, data)
#define MREPEAT145(macro, data) MREPEAT144(macro, data) macro(144, data)
#define MREPEAT146(macro, data) MREPEAT145(macro, data) macro(145, data)
#define MREPEAT147(macro, data) MREPEAT146(macro, data) macro(146, data)
#define MREPEAT148(macro, data) MREPEAT147(macro, data) macro(147, data)
#define MREPEAT149(macro, data) MREPEAT148(macro, data) macro(148, data)
#define MREPEAT150(macro, data) MREPEAT149(macro, data) macro(149, data)
#define MREPEAT151(macro, data) MREPEAT150(macro, data) macro(150, data)
#define MREPEAT152(macro, data) MREPEAT151(macro, data) macro(151, data)
#define MREPEAT153(macro, data) MREPEAT152(macro, data) macro(152, data)
#define MREPEAT154(macro, data) MREPEAT153(macro, data) macro(153, data)
#define MREPEAT155(macro, data) MREPEAT154(macro, data) macro(154, data)
#define MREPEAT156(macro, data) MREPEAT155(macro, data) macro(155, data)
#define MREPEAT157(macro, data) MREPEAT156(macro, data) macro(156, data)
#define MREPEAT158(macro, data) MREPEAT157(macro, data) macro(157, data)
#define MREPEAT159(macro, data) MREPEAT158(macro, data) macro(158, data)
#define MREPEAT160(macro, data) MREPEAT159(macro, data) macro(159, data)
#define MREPEAT161(macro, data) MREPEAT160(macro, data) macro(160, data)
#define MREPEAT162(macro, data) MREPEAT161(macro, data) macro(161, data)
#define MREPEAT163(macro, data) MREPEAT162(macro, data) macro(162, data)
#define MREPEAT164(macro, data) MREPEAT163(macro, data) macro(163, data)
#define MREPEAT165(macro, data) MREPEAT164(macro, data) macro(164, data)
#define MREPEAT166(macro, data) MREPEAT165(macro, data) macro(165, data)
#define MREPEAT167(macro, data) MREPEAT166(macro, data) macro(166, data)
#define MREPEAT168(macro, data) MREPEAT167(macro, data) macro(167, data)
#define MREPEAT169(macro, data) MREPEAT168(macro, data) macro(168, data)
#define MREPEAT170(macro, data) MREPEAT169(macro, data) macro(169, data)
#define MREPEAT171(macro, data) MREPEAT170(macro, data) macro(170, data)
#define MREPEAT172(macro, data) MREPEAT171(macro, data) macro(171, data)
#define MREPEAT173(macro, data) MREPEAT172(macro, data) macro(172, data)
#define MREPEAT174(macro, data) MREPEAT173(macro, data) macro(173, data)
#define MREPEAT175(macro, data) MREPEAT174(macro, data) macro(174, data)
#define MREPEAT176(macro, data) MREPEAT175(macro, data) macro(175, data)
#define MREPEAT177(macro, data) MREPEAT176(macro, data) macro(176, data)
#define MREPEAT178(macro, data) MREPEAT177(macro, data) macro(177, data)
#define MREPEAT179(macro, data) MREPEAT178(macro, data) macro(178, data)
#define MREPEAT180(macro, data) MREPEAT179(macro, data) macro(179, data)
#define MREPEAT181(macro, data) MREPEAT180(macro, data) macro(180, data)
#define MREPEAT182(macro, data) MREPEAT181(macro, data) macro(181, data)
#define MREPEAT183(macro, data) MREPEAT182(macro, data) macro(182, data)
#define MREPEAT184(macro, data) MREPEAT183(macro, data) macro(183, data)
#define MREPEAT185(macro, data) MREPEAT184(macro, data) macro(184, data)
#define MREPEAT186(macro, data) MREPEAT185(macro, data) macro(185, data)
#define MREPEAT187(macro, data) MREPEAT186(macro, data) macro(186, data)
#define MREPEAT188(macro, data) MREPEAT187(macro, data) macro(187, data)
#define MREPEAT189(macro, data) MREPEAT188(macro, data) macro(188, data)
#define MREPEAT190(macro, data) MREPEAT189(macro, data) macro(189, data)
#define MREPEAT191(macro, data) MREPEAT190(macro, data) macro(190, data)
#define MREPEAT192(macro, data) MREPEAT191(macro, data) macro(191, data)
#define MREPEAT193(macro, data) MREPEAT192(macro, data) macro(192, data)
#define MREPEAT194(macro, data) MREPEAT193(macro, data) macro(193, data)
#define MREPEAT195(macro, data) MREPEAT194(macro, data) macro(194, data)
#define MREPEAT196(macro, data) MREPEAT195(macro, data) macro(195, data)
#define MREPEAT197(macro, data) MREPEAT196(macro, data) macro(196, data)
#define MREPEAT198(macro, data) MREPEAT197(macro, data) macro(197, data)
#define MREPEAT199(macro, data) MREPEAT198(macro, data) macro(198, data)
#define MREPEAT200(macro, data) MREPEAT199(macro, data) macro(199, data)
#define MREPEAT201(macro, data) MREPEAT200(macro, data) macro(200, data)
#define MREPEAT202(macro, data) MREPEAT201(macro, data) macro(201, data)
#define MREPEAT203(macro, data) MREPEAT202(macro, data) macro(202, data)
#define MREPEAT204(macro, data) MREPEAT203(macro, data) macro(203, data)
#define MREPEAT205(macro, data) MREPEAT204(macro, data) macro(204, data)
#define MREPEAT206(macro, data) MREPEAT205(macro, data) macro(205, data)
#define MREPEAT207(macro, data) MREPEAT206(macro, data) macro(206, data)
#define MREPEAT208(macro, data) MREPEAT207(macro, data) macro(207, data)
#define MREPEAT209(macro, data) MREPEAT208(macro, data) macro(208, data)
#define MREPEAT210(macro, data) MREPEAT209(macro, data) macro(209, data)
#define MREPEAT211(macro, data) MREPEAT210(macro, data) macro(210, data)
#define MREPEAT212(macro, data) MREPEAT211(macro, data) macro(211, data)
#define MREPEAT213(macro, data) MREPEAT212(macro, data) macro(212, data)
#define MREPEAT214(macro, data) MREPEAT213(macro, data) macro(213, data)
#define MREPEAT215(macro, data) MREPEAT214(macro, data) macro(214, data)
#define MREPEAT216(macro, data) MREPEAT215(macro, data) macro(215, data)
#define MREPEAT217(macro, data) MREPEAT216(macro, data) macro(216, data)
#define MREPEAT218(macro, data) MREPEAT217(macro, data) macro(217, data)
#define MREPEAT219(macro, data) MREPEAT218(macro, data) macro(218, data)
#define MREPEAT220(macro, data) MREPEAT219(macro, data) macro(219, data)
#define MREPEAT221(macro, data) MREPEAT220(macro, data) macro(220, data)
#define MREPEAT222(macro, data) MREPEAT221(macro, data) macro(221, data)
#define MREPEAT223(macro, data) MREPEAT222(macro, data) macro(222, data)
#define MREPEAT224(macro, data) MREPEAT223(macro, data) macro(223, data)
#define MREPEAT225(macro, data) MREPEAT224(macro, data) macro(224, data)
#define MREPEAT226(macro, data) MREPEAT225(macro, data) macro(225, data)
#define MREPEAT227(macro, data) MREPEAT226(macro, data) macro(226, data)
#define MREPEAT228(macro, data) MREPEAT227(macro, data) macro(227, data)
#define MREPEAT229(macro, data) MREPEAT228(macro, data) macro(228, data)
#define MREPEAT230(macro, data) MREPEAT229(macro, data) macro(229, data)
#define MREPEAT231(macro, data) MREPEAT230(macro, data) macro(230, data)
#define MREPEAT232(macro, data) MREPEAT231(macro, data) macro(231, data)
#define MREPEAT233(macro, data) MREPEAT232(macro, data) macro(232, data)
#define MREPEAT234(macro, data) MREPEAT233(macro, data) macro(233, data)
#define MREPEAT235(macro, data) MREPEAT234(macro, data) macro(234, data)
#define MREPEAT236(macro, data) MREPEAT235(macro, data) macro(235, data)
#define MREPEAT237(macro, data) MREPEAT236(macro, data) macro(236, data)
#define MREPEAT238(macro, data) MREPEAT237(macro, data) macro(237, data)
#define MREPEAT239(macro, data) MREPEAT238(macro, data) macro(238, data)
#define MREPEAT240(macro, data) MREPEAT239(macro, data) macro(239, data)
#define MREPEAT241(macro, data) MREPEAT240(macro, data) macro(240, data)
#define MREPEAT242(macro, data) MREPEAT241(macro, data) macro(241, data)
#define MREPEAT243(macro, data) MREPEAT242(macro, data) macro(242, data)
#define MREPEAT244(macro, data) MREPEAT243(macro, data) macro(243, data)
#define MREPEAT245(macro, data) MREPEAT244(macro, data) macro(244, data)
#define MREPEAT246(macro, data) MREPEAT245(macro, data) macro(245, data)
#define MREPEAT247(macro, data) MREPEAT246(macro, data) macro(246, data)
#define MREPEAT248(macro, data) MREPEAT247(macro, data) macro(247, data)
#define MREPEAT249(macro, data) MREPEAT248(macro, data) macro(248, data)
#define MREPEAT250(macro, data) MREPEAT249(macro, data) macro(249, data)
#define MREPEAT251(macro, data) MREPEAT250(macro, data) macro(250, data)
#define MREPEAT252(macro, data) MREPEAT251(macro, data) macro(251, data)
#define MREPEAT253(macro, data) MREPEAT252(macro, data) macro(252, data)
#define MREPEAT254(macro, data) MREPEAT253(macro, data) macro(253, data)
#define MREPEAT255(macro, data) MREPEAT254(macro, data) macro(254, data)
#define MREPEAT256(macro, data) MREPEAT255(macro, data) macro(255, data)
/**
* \}
*/
#endif // _MREPEAT_H_

261
src/HAL/DUE/usb/osc.h Normal file
View File

@ -0,0 +1,261 @@
/**
* \file
*
* \brief Chip-specific oscillator management functions.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CHIP_OSC_H_INCLUDED
#define CHIP_OSC_H_INCLUDED
#include "compiler.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/*
* Below BOARD_XXX macros are related to the specific board, and
* should be defined by the board code, otherwise default value are used.
*/
#ifndef BOARD_FREQ_SLCK_XTAL
# warning The board slow clock xtal frequency has not been defined.
# define BOARD_FREQ_SLCK_XTAL (32768UL)
#endif
#ifndef BOARD_FREQ_SLCK_BYPASS
# warning The board slow clock bypass frequency has not been defined.
# define BOARD_FREQ_SLCK_BYPASS (32768UL)
#endif
#ifndef BOARD_FREQ_MAINCK_XTAL
# warning The board main clock xtal frequency has not been defined.
# define BOARD_FREQ_MAINCK_XTAL (12000000UL)
#endif
#ifndef BOARD_FREQ_MAINCK_BYPASS
# warning The board main clock bypass frequency has not been defined.
# define BOARD_FREQ_MAINCK_BYPASS (12000000UL)
#endif
#ifndef BOARD_OSC_STARTUP_US
# warning The board main clock xtal startup time has not been defined.
# define BOARD_OSC_STARTUP_US (15625UL)
#endif
/**
* \weakgroup osc_group
* @{
*/
//! \name Oscillator identifiers
//@{
#define OSC_SLCK_32K_RC 0 //!< Internal 32kHz RC oscillator.
#define OSC_SLCK_32K_XTAL 1 //!< External 32kHz crystal oscillator.
#define OSC_SLCK_32K_BYPASS 2 //!< External 32kHz bypass oscillator.
#define OSC_MAINCK_4M_RC 3 //!< Internal 4MHz RC oscillator.
#define OSC_MAINCK_8M_RC 4 //!< Internal 8MHz RC oscillator.
#define OSC_MAINCK_12M_RC 5 //!< Internal 12MHz RC oscillator.
#define OSC_MAINCK_XTAL 6 //!< External crystal oscillator.
#define OSC_MAINCK_BYPASS 7 //!< External bypass oscillator.
//@}
//! \name Oscillator clock speed in hertz
//@{
#define OSC_SLCK_32K_RC_HZ CHIP_FREQ_SLCK_RC //!< Internal 32kHz RC oscillator.
#define OSC_SLCK_32K_XTAL_HZ BOARD_FREQ_SLCK_XTAL //!< External 32kHz crystal oscillator.
#define OSC_SLCK_32K_BYPASS_HZ BOARD_FREQ_SLCK_BYPASS //!< External 32kHz bypass oscillator.
#define OSC_MAINCK_4M_RC_HZ CHIP_FREQ_MAINCK_RC_4MHZ //!< Internal 4MHz RC oscillator.
#define OSC_MAINCK_8M_RC_HZ CHIP_FREQ_MAINCK_RC_8MHZ //!< Internal 8MHz RC oscillator.
#define OSC_MAINCK_12M_RC_HZ CHIP_FREQ_MAINCK_RC_12MHZ //!< Internal 12MHz RC oscillator.
#define OSC_MAINCK_XTAL_HZ BOARD_FREQ_MAINCK_XTAL //!< External crystal oscillator.
#define OSC_MAINCK_BYPASS_HZ BOARD_FREQ_MAINCK_BYPASS //!< External bypass oscillator.
//@}
static inline void osc_enable(uint32_t ul_id)
{
switch (ul_id) {
case OSC_SLCK_32K_RC:
break;
case OSC_SLCK_32K_XTAL:
pmc_switch_sclk_to_32kxtal(PMC_OSC_XTAL);
break;
case OSC_SLCK_32K_BYPASS:
pmc_switch_sclk_to_32kxtal(PMC_OSC_BYPASS);
break;
case OSC_MAINCK_4M_RC:
pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_4_MHz);
break;
case OSC_MAINCK_8M_RC:
pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_8_MHz);
break;
case OSC_MAINCK_12M_RC:
pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz);
break;
case OSC_MAINCK_XTAL:
pmc_switch_mainck_to_xtal(PMC_OSC_XTAL/*,
pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US,
OSC_SLCK_32K_RC_HZ)*/);
break;
case OSC_MAINCK_BYPASS:
pmc_switch_mainck_to_xtal(PMC_OSC_BYPASS/*,
pmc_us_to_moscxtst(BOARD_OSC_STARTUP_US,
OSC_SLCK_32K_RC_HZ)*/);
break;
}
}
static inline void osc_disable(uint32_t ul_id)
{
switch (ul_id) {
case OSC_SLCK_32K_RC:
case OSC_SLCK_32K_XTAL:
case OSC_SLCK_32K_BYPASS:
break;
case OSC_MAINCK_4M_RC:
case OSC_MAINCK_8M_RC:
case OSC_MAINCK_12M_RC:
pmc_osc_disable_fastrc();
break;
case OSC_MAINCK_XTAL:
pmc_osc_disable_xtal(PMC_OSC_XTAL);
break;
case OSC_MAINCK_BYPASS:
pmc_osc_disable_xtal(PMC_OSC_BYPASS);
break;
}
}
static inline bool osc_is_ready(uint32_t ul_id)
{
switch (ul_id) {
case OSC_SLCK_32K_RC:
return 1;
case OSC_SLCK_32K_XTAL:
case OSC_SLCK_32K_BYPASS:
return pmc_osc_is_ready_32kxtal();
case OSC_MAINCK_4M_RC:
case OSC_MAINCK_8M_RC:
case OSC_MAINCK_12M_RC:
case OSC_MAINCK_XTAL:
case OSC_MAINCK_BYPASS:
return pmc_osc_is_ready_mainck();
}
return 0;
}
static inline uint32_t osc_get_rate(uint32_t ul_id)
{
switch (ul_id) {
case OSC_SLCK_32K_RC:
return OSC_SLCK_32K_RC_HZ;
case OSC_SLCK_32K_XTAL:
return BOARD_FREQ_SLCK_XTAL;
case OSC_SLCK_32K_BYPASS:
return BOARD_FREQ_SLCK_BYPASS;
case OSC_MAINCK_4M_RC:
return OSC_MAINCK_4M_RC_HZ;
case OSC_MAINCK_8M_RC:
return OSC_MAINCK_8M_RC_HZ;
case OSC_MAINCK_12M_RC:
return OSC_MAINCK_12M_RC_HZ;
case OSC_MAINCK_XTAL:
return BOARD_FREQ_MAINCK_XTAL;
case OSC_MAINCK_BYPASS:
return BOARD_FREQ_MAINCK_BYPASS;
}
return 0;
}
/**
* \brief Wait until the oscillator identified by \a id is ready
*
* This function will busy-wait for the oscillator identified by \a id
* to become stable and ready to use as a clock source.
*
* \param id A number identifying the oscillator to wait for.
*/
static inline void osc_wait_ready(uint8_t id)
{
while (!osc_is_ready(id)) {
/* Do nothing */
}
}
//! @}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* CHIP_OSC_H_INCLUDED */

288
src/HAL/DUE/usb/pll.h Normal file
View File

@ -0,0 +1,288 @@
/**
* \file
*
* \brief Chip-specific PLL definitions.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CHIP_PLL_H_INCLUDED
#define CHIP_PLL_H_INCLUDED
#include "osc.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \weakgroup pll_group
* @{
*/
#define PLL_OUTPUT_MIN_HZ 84000000
#define PLL_OUTPUT_MAX_HZ 192000000
#define PLL_INPUT_MIN_HZ 8000000
#define PLL_INPUT_MAX_HZ 16000000
#define NR_PLLS 2
#define PLLA_ID 0
#define UPLL_ID 1 //!< USB UTMI PLL.
#define PLL_UPLL_HZ 480000000
#define PLL_COUNT 0x3FU
enum pll_source {
PLL_SRC_MAINCK_4M_RC = OSC_MAINCK_4M_RC, //!< Internal 4MHz RC oscillator.
PLL_SRC_MAINCK_8M_RC = OSC_MAINCK_8M_RC, //!< Internal 8MHz RC oscillator.
PLL_SRC_MAINCK_12M_RC = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator.
PLL_SRC_MAINCK_XTAL = OSC_MAINCK_XTAL, //!< External crystal oscillator.
PLL_SRC_MAINCK_BYPASS = OSC_MAINCK_BYPASS, //!< External bypass oscillator.
PLL_NR_SOURCES, //!< Number of PLL sources.
};
struct pll_config {
uint32_t ctrl;
};
#define pll_get_default_rate(pll_id) \
((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE) \
* CONFIG_PLL##pll_id##_MUL) \
/ CONFIG_PLL##pll_id##_DIV)
/* Force UTMI PLL parameters (Hardware defined) */
#ifdef CONFIG_PLL1_SOURCE
# undef CONFIG_PLL1_SOURCE
#endif
#ifdef CONFIG_PLL1_MUL
# undef CONFIG_PLL1_MUL
#endif
#ifdef CONFIG_PLL1_DIV
# undef CONFIG_PLL1_DIV
#endif
#define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_XTAL
#define CONFIG_PLL1_MUL 0
#define CONFIG_PLL1_DIV 0
/**
* \note The SAM3X PLL hardware interprets mul as mul+1. For readability the hardware mul+1
* is hidden in this implementation. Use mul as mul effective value.
*/
static inline void pll_config_init(struct pll_config *p_cfg,
enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul)
{
uint32_t vco_hz;
Assert(e_src < PLL_NR_SOURCES);
if (ul_div == 0 && ul_mul == 0) { /* Must only be true for UTMI PLL */
p_cfg->ctrl = CKGR_UCKR_UPLLCOUNT(PLL_COUNT);
} else { /* PLLA */
/* Calculate internal VCO frequency */
vco_hz = osc_get_rate(e_src) / ul_div;
Assert(vco_hz >= PLL_INPUT_MIN_HZ);
Assert(vco_hz <= PLL_INPUT_MAX_HZ);
vco_hz *= ul_mul;
Assert(vco_hz >= PLL_OUTPUT_MIN_HZ);
Assert(vco_hz <= PLL_OUTPUT_MAX_HZ);
/* PMC hardware will automatically make it mul+1 */
p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div) | CKGR_PLLAR_PLLACOUNT(PLL_COUNT);
}
}
#define pll_config_defaults(cfg, pll_id) \
pll_config_init(cfg, \
CONFIG_PLL##pll_id##_SOURCE, \
CONFIG_PLL##pll_id##_DIV, \
CONFIG_PLL##pll_id##_MUL)
static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id)
{
Assert(ul_pll_id < NR_PLLS);
if (ul_pll_id == PLLA_ID) {
p_cfg->ctrl = PMC->CKGR_PLLAR;
} else {
p_cfg->ctrl = PMC->CKGR_UCKR;
}
}
static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id)
{
Assert(ul_pll_id < NR_PLLS);
if (ul_pll_id == PLLA_ID) {
pmc_disable_pllack(); // Always stop PLL first!
PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl;
} else {
PMC->CKGR_UCKR = p_cfg->ctrl;
}
}
static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id)
{
Assert(ul_pll_id < NR_PLLS);
if (ul_pll_id == PLLA_ID) {
pmc_disable_pllack(); // Always stop PLL first!
PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl;
} else {
PMC->CKGR_UCKR = p_cfg->ctrl | CKGR_UCKR_UPLLEN;
}
}
/**
* \note This will only disable the selected PLL, not the underlying oscillator (mainck).
*/
static inline void pll_disable(uint32_t ul_pll_id)
{
Assert(ul_pll_id < NR_PLLS);
if (ul_pll_id == PLLA_ID) {
pmc_disable_pllack();
} else {
PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN;
}
}
static inline uint32_t pll_is_locked(uint32_t ul_pll_id)
{
Assert(ul_pll_id < NR_PLLS);
if (ul_pll_id == PLLA_ID) {
return pmc_is_locked_pllack();
} else {
return pmc_is_locked_upll();
}
}
static inline void pll_enable_source(enum pll_source e_src)
{
switch (e_src) {
case PLL_SRC_MAINCK_4M_RC:
case PLL_SRC_MAINCK_8M_RC:
case PLL_SRC_MAINCK_12M_RC:
case PLL_SRC_MAINCK_XTAL:
case PLL_SRC_MAINCK_BYPASS:
osc_enable(e_src);
osc_wait_ready(e_src);
break;
default:
Assert(false);
break;
}
}
static inline void pll_enable_config_defaults(unsigned int ul_pll_id)
{
struct pll_config pllcfg;
if (pll_is_locked(ul_pll_id)) {
return; // Pll already running
}
switch (ul_pll_id) {
#ifdef CONFIG_PLL0_SOURCE
case 0:
pll_enable_source(CONFIG_PLL0_SOURCE);
pll_config_init(&pllcfg,
CONFIG_PLL0_SOURCE,
CONFIG_PLL0_DIV,
CONFIG_PLL0_MUL);
break;
#endif
#ifdef CONFIG_PLL1_SOURCE
case 1:
pll_enable_source(CONFIG_PLL1_SOURCE);
pll_config_init(&pllcfg,
CONFIG_PLL1_SOURCE,
CONFIG_PLL1_DIV,
CONFIG_PLL1_MUL);
break;
#endif
default:
Assert(false);
break;
}
pll_enable(&pllcfg, ul_pll_id);
while (!pll_is_locked(ul_pll_id));
}
/**
* \brief Wait for PLL \a pll_id to become locked
*
* \todo Use a timeout to avoid waiting forever and hanging the system
*
* \param pll_id The ID of the PLL to wait for.
*
* \retval STATUS_OK The PLL is now locked.
* \retval ERR_TIMEOUT Timed out waiting for PLL to become locked.
*/
static inline int pll_wait_for_lock(unsigned int pll_id)
{
Assert(pll_id < NR_PLLS);
while (!pll_is_locked(pll_id)) {
/* Do nothing */
}
return 0;
}
//! @}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* CHIP_PLL_H_INCLUDED */

View File

@ -0,0 +1,55 @@
/**
* \file
*
* \brief Preprocessor utils.
*
* Copyright (c) 2010-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _PREPROCESSOR_H_
#define _PREPROCESSOR_H_
#include "tpaste.h"
#include "stringz.h"
#include "mrepeat.h"
#endif // _PREPROCESSOR_H_

View File

@ -0,0 +1,173 @@
/**
* \file
*
* \brief SCSI Block Commands
*
* This file contains definitions of some of the commands found in the
* SCSI SBC-2 standard.
*
* Note that the SBC specification depends on several commands defined
* by the SCSI Primary Commands (SPC) standard. Each version of the SBC
* standard is meant to be used in conjunction with a specific version
* of the SPC standard, as follows:
* - SBC depends on SPC
* - SBC-2 depends on SPC-3
* - SBC-3 depends on SPC-4
*
* Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _SBC_PROTOCOL_H_
#define _SBC_PROTOCOL_H_
/**
* \ingroup usb_msc_protocol
* \defgroup usb_sbc_protocol SCSI Block Commands protocol definitions
*
* @{
*/
//! \name SCSI commands defined by SBC-2
//@{
#define SBC_FORMAT_UNIT 0x04
#define SBC_READ6 0x08
#define SBC_WRITE6 0x0A
#define SBC_START_STOP_UNIT 0x1B
#define SBC_READ_CAPACITY10 0x25
#define SBC_READ10 0x28
#define SBC_WRITE10 0x2A
#define SBC_VERIFY10 0x2F
//@}
//! \name SBC-2 Mode page definitions
//@{
enum scsi_sbc_mode {
SCSI_MS_MODE_RW_ERR_RECOV = 0x01, //!< Read-Write Error Recovery mode page
SCSI_MS_MODE_FORMAT_DEVICE = 0x03, //!< Format Device mode page
SCSI_MS_MODE_FLEXIBLE_DISK = 0x05, //!< Flexible Disk mode page
SCSI_MS_MODE_CACHING = 0x08, //!< Caching mode page
};
//! \name SBC-2 Device-Specific Parameter
//@{
#define SCSI_MS_SBC_WP 0x80 //!< Write Protected
#define SCSI_MS_SBC_DPOFUA 0x10 //!< DPO and FUA supported
//@}
/**
* \brief SBC-2 Short LBA mode parameter block descriptor
*/
struct sbc_slba_block_desc {
be32_t nr_blocks; //!< Number of Blocks
be32_t block_len; //!< Block Length
#define SBC_SLBA_BLOCK_LEN_MASK 0x00FFFFFFU //!< Mask reserved bits
};
/**
* \brief SBC-2 Caching mode page
*/
struct sbc_caching_mode_page {
uint8_t page_code;
uint8_t page_length;
uint8_t flags2;
#define SBC_MP_CACHE_IC (1 << 7) //!< Initiator Control
#define SBC_MP_CACHE_ABPF (1 << 6) //!< Abort Pre-Fetch
#define SBC_MP_CACHE_CAP (1 << 5) //!< Catching Analysis Permitted
#define SBC_MP_CACHE_DISC (1 << 4) //!< Discontinuity
#define SBC_MP_CACHE_SIZE (1 << 3) //!< Size enable
#define SBC_MP_CACHE_WCE (1 << 2) //!< Write back Cache Enable
#define SBC_MP_CACHE_MF (1 << 1) //!< Multiplication Factor
#define SBC_MP_CACHE_RCD (1 << 0) //!< Read Cache Disable
uint8_t retention;
be16_t dis_pf_transfer_len;
be16_t min_prefetch;
be16_t max_prefetch;
be16_t max_prefetch_ceil;
uint8_t flags12;
#define SBC_MP_CACHE_FSW (1 << 7) //!< Force Sequential Write
#define SBC_MP_CACHE_LBCSS (1 << 6) //!< Logical Blk Cache Seg Sz
#define SBC_MP_CACHE_DRA (1 << 5) //!< Disable Read-Ahead
#define SBC_MP_CACHE_NV_DIS (1 << 0) //!< Non-Volatile Cache Disable
uint8_t nr_cache_segments;
be16_t cache_segment_size;
uint8_t reserved[4];
};
/**
* \brief SBC-2 Read-Write Error Recovery mode page
*/
struct sbc_rdwr_error_recovery_mode_page {
uint8_t page_code;
uint8_t page_length;
#define SPC_MP_RW_ERR_RECOV_PAGE_LENGTH 0x0A
uint8_t flags1;
#define SBC_MP_RW_ERR_RECOV_AWRE (1 << 7)
#define SBC_MP_RW_ERR_RECOV_ARRE (1 << 6)
#define SBC_MP_RW_ERR_RECOV_TB (1 << 5)
#define SBC_MP_RW_ERR_RECOV_RC (1 << 4)
#define SBC_MP_RW_ERR_RECOV_ERR (1 << 3)
#define SBC_MP_RW_ERR_RECOV_PER (1 << 2)
#define SBC_MP_RW_ERR_RECOV_DTE (1 << 1)
#define SBC_MP_RW_ERR_RECOV_DCR (1 << 0)
uint8_t read_retry_count;
uint8_t correction_span;
uint8_t head_offset_count;
uint8_t data_strobe_offset_count;
uint8_t flags2;
uint8_t write_retry_count;
uint8_t flags3;
be16_t recovery_time_limit;
};
//@}
/**
* \brief SBC-2 READ CAPACITY (10) parameter data
*/
struct sbc_read_capacity10_data {
be32_t max_lba; //!< LBA of last logical block
be32_t block_len; //!< Number of bytes in the last logical block
};
//@}
#endif // _SBC_PROTOCOL_H_

View File

@ -0,0 +1,142 @@
/**
* Interface from Atmel USB MSD to Marlin SD card
*/
#ifdef ARDUINO_ARCH_SAM
#include "../../../inc/MarlinConfig.h"
#if ENABLED(SDSUPPORT)
#include "../../../sd/cardreader.h"
extern "C" {
#include "sd_mmc_spi_mem.h"
}
#define SD_MMC_BLOCK_SIZE 512
void sd_mmc_spi_mem_init() {
}
Ctrl_status sd_mmc_spi_test_unit_ready() {
#ifdef DISABLE_DUE_SD_MMC
return CTRL_NO_PRESENT;
#endif
if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted())
return CTRL_NO_PRESENT;
return CTRL_GOOD;
}
// NOTE: This function is defined as returning the address of the last block
// in the card, which is cardSize() - 1
Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector) {
if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted())
return CTRL_NO_PRESENT;
*nb_sector = card.diskIODriver()->cardSize() - 1;
return CTRL_GOOD;
}
bool sd_mmc_spi_unload(bool) { return true; }
bool sd_mmc_spi_wr_protect() { return false; }
bool sd_mmc_spi_removal() {
return (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted());
}
#if ACCESS_USB == true
/**
* \name MEM <-> USB Interface
* @{
*/
#include "udi_msc.h"
COMPILER_WORD_ALIGNED
uint8_t sector_buf[SD_MMC_BLOCK_SIZE];
// #define DEBUG_MMC
Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector) {
#ifdef DISABLE_DUE_SD_MMC
return CTRL_NO_PRESENT;
#endif
if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted())
return CTRL_NO_PRESENT;
#ifdef DEBUG_MMC
{
char buffer[80];
sprintf_P(buffer, PSTR("SDRD: %d @ 0x%08x\n"), nb_sector, addr);
PORT_REDIRECT(SERIAL_PORTMASK(0));
SERIAL_ECHO(buffer);
}
#endif
// Start reading
if (!card.diskIODriver()->readStart(addr))
return CTRL_FAIL;
// For each specified sector
while (nb_sector--) {
// Read a sector
card.diskIODriver()->readData(sector_buf);
// RAM -> USB
if (!udi_msc_trans_block(true, sector_buf, SD_MMC_BLOCK_SIZE, nullptr)) {
card.diskIODriver()->readStop();
return CTRL_FAIL;
}
}
// Stop reading
card.diskIODriver()->readStop();
// Done
return CTRL_GOOD;
}
Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector) {
#ifdef DISABLE_DUE_SD_MMC
return CTRL_NO_PRESENT;
#endif
if (!IS_SD_INSERTED() || IS_SD_PRINTING() || IS_SD_FILE_OPEN() || !card.isMounted())
return CTRL_NO_PRESENT;
#ifdef DEBUG_MMC
{
char buffer[80];
sprintf_P(buffer, PSTR("SDWR: %d @ 0x%08x\n"), nb_sector, addr);
PORT_REDIRECT(SERIAL_PORTMASK(0));
SERIAL_ECHO(buffer);
}
#endif
if (!card.diskIODriver()->writeStart(addr, nb_sector))
return CTRL_FAIL;
// For each specified sector
while (nb_sector--) {
// USB -> RAM
if (!udi_msc_trans_block(false, sector_buf, SD_MMC_BLOCK_SIZE, nullptr)) {
card.diskIODriver()->writeStop();
return CTRL_FAIL;
}
// Write a sector
card.diskIODriver()->writeData(sector_buf);
}
// Stop writing
card.diskIODriver()->writeStop();
// Done
return CTRL_GOOD;
}
#endif // ACCESS_USB == true
#endif // SDSUPPORT
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,177 @@
/*****************************************************************************
*
* \file
*
* \brief CTRL_ACCESS interface for SD/MMC card.
*
* Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
******************************************************************************/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _SD_MMC_SPI_MEM_H_
#define _SD_MMC_SPI_MEM_H_
/**
* \defgroup group_avr32_components_memory_sd_mmc_sd_mmc_spi_mem SD/MMC SPI Memory
*
* \ingroup group_avr32_components_memory_sd_mmc_sd_mmc_spi
*
* \{
*/
#include "conf_access.h"
#if SD_MMC_SPI_MEM == DISABLE
#error sd_mmc_spi_mem.h is #included although SD_MMC_SPI_MEM is disabled
#endif
#include "ctrl_access.h"
//_____ D E F I N I T I O N S ______________________________________________
#define SD_MMC_REMOVED 0
#define SD_MMC_INSERTED 1
#define SD_MMC_REMOVING 2
//---- CONTROL FUNCTIONS ----
//!
//! @brief This function initializes the hw/sw resources required to drive the SD_MMC_SPI.
//!/
extern void sd_mmc_spi_mem_init(void);
//!
//! @brief This function tests the state of the SD_MMC memory and sends it to the Host.
//! For a PC, this device is seen as a removable media
//! Before indicating any modification of the status of the media (GOOD->NO_PRESENT or vice-versa),
//! the function must return the BUSY data to make the PC accepting the change
//!
//! @return Ctrl_status
//! Media is ready -> CTRL_GOOD
//! Media not present -> CTRL_NO_PRESENT
//! Media has changed -> CTRL_BUSY
//!/
extern Ctrl_status sd_mmc_spi_test_unit_ready(void);
//!
//! @brief This function gives the address of the last valid sector.
//!
//! @param *nb_sector number of sector (sector = 512B). OUT
//!
//! @return Ctrl_status
//! Media ready -> CTRL_GOOD
//! Media not present -> CTRL_NO_PRESENT
//!/
extern Ctrl_status sd_mmc_spi_read_capacity(uint32_t *nb_sector);
/*! \brief Unload/Load the SD/MMC card selected
*
* The START STOP UNIT SCSI optional command allows an application client to
* eject the removable medium on a LUN.
*
* \param unload \c true to unload the medium, \c false to load the medium.
*
* \return \c true if unload/load done success.
*/
extern bool sd_mmc_spi_unload(bool unload);
//!
//! @brief This function returns the write protected status of the memory.
//!
//! Only used by memory removal with a HARDWARE SPECIFIC write protected detection
//! ! The user must unplug the memory to change this write protected status,
//! which cannot be for a SD_MMC.
//!
//! @return false -> the memory is not write-protected (always)
//!/
extern bool sd_mmc_spi_wr_protect(void);
//!
//! @brief This function tells if the memory has been removed or not.
//!
//! @return false -> The memory isn't removed
//!
extern bool sd_mmc_spi_removal(void);
//---- ACCESS DATA FUNCTIONS ----
#if ACCESS_USB == true
// Standard functions for open in read/write mode the device
//!
//! @brief This function performs a read operation of n sectors from a given address on.
//! (sector = 512B)
//!
//! DATA FLOW is: SD_MMC => USB
//!
//! @param addr Sector address to start the read from
//! @param nb_sector Number of sectors to transfer
//!
//! @return Ctrl_status
//! It is ready -> CTRL_GOOD
//! A error occur -> CTRL_FAIL
//!
extern Ctrl_status sd_mmc_spi_usb_read_10(uint32_t addr, uint16_t nb_sector);
//! This function initializes the SD/MMC memory for a write operation
//!
//! DATA FLOW is: USB => SD_MMC
//!
//! (sector = 512B)
//! @param addr Sector address to start write
//! @param nb_sector Number of sectors to transfer
//!
//! @return Ctrl_status
//! It is ready -> CTRL_GOOD
//! An error occurs -> CTRL_FAIL
//!
extern Ctrl_status sd_mmc_spi_usb_write_10(uint32_t addr, uint16_t nb_sector);
#endif // #if ACCESS_USB == true
/**
* \}
*/
#endif // _SD_MMC_SPI_MEM_H_

View File

@ -0,0 +1,337 @@
/**
* \file
*
* \brief SCSI Primary Commands
*
* This file contains definitions of some of the commands found in the
* SPC-2 standard.
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _SPC_PROTOCOL_H_
#define _SPC_PROTOCOL_H_
/**
* \ingroup usb_msc_protocol
* \defgroup usb_spc_protocol SCSI Primary Commands protocol definitions
*
* @{
*/
//! \name SCSI commands defined by SPC-2
//@{
#define SPC_TEST_UNIT_READY 0x00
#define SPC_REQUEST_SENSE 0x03
#define SPC_INQUIRY 0x12
#define SPC_MODE_SELECT6 0x15
#define SPC_MODE_SENSE6 0x1A
#define SPC_SEND_DIAGNOSTIC 0x1D
#define SPC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
#define SPC_MODE_SENSE10 0x5A
#define SPC_REPORT_LUNS 0xA0
//@}
//! \brief May be set in byte 0 of the INQUIRY CDB
//@{
//! Enable Vital Product Data
#define SCSI_INQ_REQ_EVPD 0x01
//! Command Support Data specified by the PAGE OR OPERATION CODE field
#define SCSI_INQ_REQ_CMDT 0x02
//@}
COMPILER_PACK_SET(1)
/**
* \brief SCSI Standard Inquiry data structure
*/
struct scsi_inquiry_data {
uint8_t pq_pdt; //!< Peripheral Qual / Peripheral Dev Type
#define SCSI_INQ_PQ_CONNECTED 0x00 //!< Peripheral connected
#define SCSI_INQ_PQ_NOT_CONN 0x20 //!< Peripheral not connected
#define SCSI_INQ_PQ_NOT_SUPP 0x60 //!< Peripheral not supported
#define SCSI_INQ_DT_DIR_ACCESS 0x00 //!< Direct Access (SBC)
#define SCSI_INQ_DT_SEQ_ACCESS 0x01 //!< Sequential Access
#define SCSI_INQ_DT_PRINTER 0x02 //!< Printer
#define SCSI_INQ_DT_PROCESSOR 0x03 //!< Processor device
#define SCSI_INQ_DT_WRITE_ONCE 0x04 //!< Write-once device
#define SCSI_INQ_DT_CD_DVD 0x05 //!< CD/DVD device
#define SCSI_INQ_DT_OPTICAL 0x07 //!< Optical Memory
#define SCSI_INQ_DT_MC 0x08 //!< Medium Changer
#define SCSI_INQ_DT_ARRAY 0x0C //!< Storage Array Controller
#define SCSI_INQ_DT_ENCLOSURE 0x0D //!< Enclosure Services
#define SCSI_INQ_DT_RBC 0x0E //!< Simplified Direct Access
#define SCSI_INQ_DT_OCRW 0x0F //!< Optical card reader/writer
#define SCSI_INQ_DT_BCC 0x10 //!< Bridge Controller Commands
#define SCSI_INQ_DT_OSD 0x11 //!< Object-based Storage
#define SCSI_INQ_DT_NONE 0x1F //!< No Peripheral
uint8_t flags1; //!< Flags (byte 1)
#define SCSI_INQ_RMB 0x80 //!< Removable Medium
uint8_t version; //!< Version
#define SCSI_INQ_VER_NONE 0x00 //!< No standards conformance
#define SCSI_INQ_VER_SPC 0x03 //!< SCSI Primary Commands (link to SBC)
#define SCSI_INQ_VER_SPC2 0x04 //!< SCSI Primary Commands - 2 (link to SBC-2)
#define SCSI_INQ_VER_SPC3 0x05 //!< SCSI Primary Commands - 3 (link to SBC-2)
#define SCSI_INQ_VER_SPC4 0x06 //!< SCSI Primary Commands - 4 (link to SBC-3)
uint8_t flags3; //!< Flags (byte 3)
#define SCSI_INQ_NORMACA 0x20 //!< Normal ACA Supported
#define SCSI_INQ_HISUP 0x10 //!< Hierarchal LUN addressing
#define SCSI_INQ_RSP_SPC2 0x02 //!< SPC-2 / SPC-3 response format
uint8_t addl_len; //!< Additional Length (n-4)
#define SCSI_INQ_ADDL_LEN(tot) ((tot)-5) //!< Total length is \a tot
uint8_t flags5; //!< Flags (byte 5)
#define SCSI_INQ_SCCS 0x80
uint8_t flags6; //!< Flags (byte 6)
#define SCSI_INQ_BQUE 0x80
#define SCSI_INQ_ENCSERV 0x40
#define SCSI_INQ_MULTIP 0x10
#define SCSI_INQ_MCHGR 0x08
#define SCSI_INQ_ADDR16 0x01
uint8_t flags7; //!< Flags (byte 7)
#define SCSI_INQ_WBUS16 0x20
#define SCSI_INQ_SYNC 0x10
#define SCSI_INQ_LINKED 0x08
#define SCSI_INQ_CMDQUE 0x02
uint8_t vendor_id[8]; //!< T10 Vendor Identification
uint8_t product_id[16]; //!< Product Identification
uint8_t product_rev[4]; //!< Product Revision Level
};
/**
* \brief SCSI Standard Request sense data structure
*/
struct scsi_request_sense_data {
/* 1st byte: REQUEST SENSE response flags*/
uint8_t valid_reponse_code;
#define SCSI_SENSE_VALID 0x80 //!< Indicates the INFORMATION field contains valid information
#define SCSI_SENSE_RESPONSE_CODE_MASK 0x7F
#define SCSI_SENSE_CURRENT 0x70 //!< Response code 70h (current errors)
#define SCSI_SENSE_DEFERRED 0x71
/* 2nd byte */
uint8_t obsolete;
/* 3rd byte */
uint8_t sense_flag_key;
#define SCSI_SENSE_FILEMARK 0x80 //!< Indicates that the current command has read a filemark or setmark.
#define SCSI_SENSE_EOM 0x40 //!< Indicates that an end-of-medium condition exists.
#define SCSI_SENSE_ILI 0x20 //!< Indicates that the requested logical block length did not match the logical block length of the data on the medium.
#define SCSI_SENSE_RESERVED 0x10 //!< Reserved
#define SCSI_SENSE_KEY(x) (x&0x0F) //!< Sense Key
/* 4th to 7th bytes - INFORMATION field */
uint8_t information[4];
/* 8th byte - ADDITIONAL SENSE LENGTH field */
uint8_t AddSenseLen;
#define SCSI_SENSE_ADDL_LEN(total_len) ((total_len) - 8)
/* 9th to 12th byte - COMMAND-SPECIFIC INFORMATION field */
uint8_t CmdSpecINFO[4];
/* 13th byte - ADDITIONAL SENSE CODE field */
uint8_t AddSenseCode;
/* 14th byte - ADDITIONAL SENSE CODE QUALIFIER field */
uint8_t AddSnsCodeQlfr;
/* 15th byte - FIELD REPLACEABLE UNIT CODE field */
uint8_t FldReplUnitCode;
/* 16th byte */
uint8_t SenseKeySpec[3];
#define SCSI_SENSE_SKSV 0x80 //!< Indicates the SENSE-KEY SPECIFIC field contains valid information
};
COMPILER_PACK_RESET()
/* Vital Product Data page codes */
enum scsi_vpd_page_code {
SCSI_VPD_SUPPORTED_PAGES = 0x00,
SCSI_VPD_UNIT_SERIAL_NUMBER = 0x80,
SCSI_VPD_DEVICE_IDENTIFICATION = 0x83,
};
#define SCSI_VPD_HEADER_SIZE 4
/* Constants associated with the Device Identification VPD page */
#define SCSI_VPD_ID_HEADER_SIZE 4
#define SCSI_VPD_CODE_SET_BINARY 1
#define SCSI_VPD_CODE_SET_ASCII 2
#define SCSI_VPD_CODE_SET_UTF8 3
#define SCSI_VPD_ID_TYPE_T10 1
/* Sense keys */
enum scsi_sense_key {
SCSI_SK_NO_SENSE = 0x0,
SCSI_SK_RECOVERED_ERROR = 0x1,
SCSI_SK_NOT_READY = 0x2,
SCSI_SK_MEDIUM_ERROR = 0x3,
SCSI_SK_HARDWARE_ERROR = 0x4,
SCSI_SK_ILLEGAL_REQUEST = 0x5,
SCSI_SK_UNIT_ATTENTION = 0x6,
SCSI_SK_DATA_PROTECT = 0x7,
SCSI_SK_BLANK_CHECK = 0x8,
SCSI_SK_VENDOR_SPECIFIC = 0x9,
SCSI_SK_COPY_ABORTED = 0xA,
SCSI_SK_ABORTED_COMMAND = 0xB,
SCSI_SK_VOLUME_OVERFLOW = 0xD,
SCSI_SK_MISCOMPARE = 0xE,
};
/* Additional Sense Code / Additional Sense Code Qualifier pairs */
enum scsi_asc_ascq {
SCSI_ASC_NO_ADDITIONAL_SENSE_INFO = 0x0000,
SCSI_ASC_LU_NOT_READY_REBUILD_IN_PROGRESS = 0x0405,
SCSI_ASC_WRITE_ERROR = 0x0C00,
SCSI_ASC_UNRECOVERED_READ_ERROR = 0x1100,
SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x2000,
SCSI_ASC_INVALID_FIELD_IN_CDB = 0x2400,
SCSI_ASC_WRITE_PROTECTED = 0x2700,
SCSI_ASC_NOT_READY_TO_READY_CHANGE = 0x2800,
SCSI_ASC_MEDIUM_NOT_PRESENT = 0x3A00,
SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x4400,
};
/**
* \brief SPC-2 Mode parameter
* This subclause describes the block descriptors and the pages
* used with MODE SELECT and MODE SENSE commands
* that are applicable to all SCSI devices.
*/
enum scsi_spc_mode {
SCSI_MS_MODE_VENDOR_SPEC = 0x00,
SCSI_MS_MODE_INFEXP = 0x1C, // Informational exceptions control page
SCSI_MS_MODE_ALL = 0x3F,
};
/**
* \brief SPC-2 Informational exceptions control page
* See chapter 8.3.8
*/
struct spc_control_page_info_execpt {
uint8_t page_code;
uint8_t page_length;
#define SPC_MP_INFEXP_PAGE_LENGTH 0x0A
uint8_t flags1;
#define SPC_MP_INFEXP_PERF (1<<7) //!< Initiator Control
#define SPC_MP_INFEXP_EBF (1<<5) //!< Caching Analysis Permitted
#define SPC_MP_INFEXP_EWASC (1<<4) //!< Discontinuity
#define SPC_MP_INFEXP_DEXCPT (1<<3) //!< Size enable
#define SPC_MP_INFEXP_TEST (1<<2) //!< Writeback Cache Enable
#define SPC_MP_INFEXP_LOGERR (1<<0) //!< Log errors bit
uint8_t mrie;
#define SPC_MP_INFEXP_MRIE_NO_REPORT 0x00
#define SPC_MP_INFEXP_MRIE_ASYNC_EVENT 0x01
#define SPC_MP_INFEXP_MRIE_GEN_UNIT 0x02
#define SPC_MP_INFEXP_MRIE_COND_RECOV_ERROR 0x03
#define SPC_MP_INFEXP_MRIE_UNCOND_RECOV_ERROR 0x04
#define SPC_MP_INFEXP_MRIE_NO_SENSE 0x05
#define SPC_MP_INFEXP_MRIE_ONLY_REPORT 0x06
be32_t interval_timer;
be32_t report_count;
};
enum scsi_spc_mode_sense_pc {
SCSI_MS_SENSE_PC_CURRENT = 0,
SCSI_MS_SENSE_PC_CHANGEABLE = 1,
SCSI_MS_SENSE_PC_DEFAULT = 2,
SCSI_MS_SENSE_PC_SAVED = 3,
};
static inline bool scsi_mode_sense_dbd_is_set(const uint8_t * cdb)
{
return (cdb[1] >> 3) & 1;
}
static inline uint8_t scsi_mode_sense_get_page_code(const uint8_t * cdb)
{
return cdb[2] & 0x3F;
}
static inline uint8_t scsi_mode_sense_get_pc(const uint8_t * cdb)
{
return cdb[2] >> 6;
}
/**
* \brief SCSI Mode Parameter Header used by MODE SELECT(6) and MODE
* SENSE(6)
*/
struct scsi_mode_param_header6 {
uint8_t mode_data_length; //!< Number of bytes after this
uint8_t medium_type; //!< Medium Type
uint8_t device_specific_parameter; //!< Defined by command set
uint8_t block_descriptor_length; //!< Length of block descriptors
};
/**
* \brief SCSI Mode Parameter Header used by MODE SELECT(10) and MODE
* SENSE(10)
*/
struct scsi_mode_param_header10 {
be16_t mode_data_length; //!< Number of bytes after this
uint8_t medium_type; //!< Medium Type
uint8_t device_specific_parameter; //!< Defined by command set
uint8_t flags4; //!< LONGLBA in bit 0
uint8_t reserved;
be16_t block_descriptor_length; //!< Length of block descriptors
};
/**
* \brief SCSI Page_0 Mode Page header (SPF not set)
*/
struct scsi_mode_page_0_header {
uint8_t page_code;
#define SCSI_PAGE_CODE_PS (1 << 7) //!< Parameters Saveable
#define SCSI_PAGE_CODE_SPF (1 << 6) //!< SubPage Format
uint8_t page_length; //!< Number of bytes after this
#define SCSI_MS_PAGE_LEN(total) ((total) - 2)
};
//@}
#endif // SPC_PROTOCOL_H_

85
src/HAL/DUE/usb/stringz.h Normal file
View File

@ -0,0 +1,85 @@
/**
* \file
*
* \brief Preprocessor stringizing utils.
*
* Copyright (c) 2010-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _STRINGZ_H_
#define _STRINGZ_H_
/**
* \defgroup group_sam_utils_stringz Preprocessor - Stringize
*
* \ingroup group_sam_utils
*
* \{
*/
/*! \brief Stringize.
*
* Stringize a preprocessing token, this token being allowed to be \#defined.
*
* May be used only within macros with the token passed as an argument if the token is \#defined.
*
* For example, writing STRINGZ(PIN) within a macro \#defined by PIN_NAME(PIN)
* and invoked as PIN_NAME(PIN0) with PIN0 \#defined as A0 is equivalent to
* writing "A0".
*/
#define STRINGZ(x) #x
/*! \brief Absolute stringize.
*
* Stringize a preprocessing token, this token being allowed to be \#defined.
*
* No restriction of use if the token is \#defined.
*
* For example, writing ASTRINGZ(PIN0) anywhere with PIN0 \#defined as A0 is
* equivalent to writing "A0".
*/
#define ASTRINGZ(x) STRINGZ(x)
/**
* \}
*/
#endif // _STRINGZ_H_

122
src/HAL/DUE/usb/sysclk.c Normal file
View File

@ -0,0 +1,122 @@
/**
* \file
*
* \brief Chip-specific system clock management functions.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifdef ARDUINO_ARCH_SAM
#include "sysclk.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \weakgroup sysclk_group
* @{
*/
#if defined(CONFIG_USBCLK_SOURCE) || defined(__DOXYGEN__)
/**
* \brief Enable full speed USB clock.
*
* \note The SAM3X PMC hardware interprets div as div+1. For readability the hardware div+1
* is hidden in this implementation. Use div as div effective value.
*
* \param pll_id Source of the USB clock.
* \param div Actual clock divisor. Must be superior to 0.
*/
void sysclk_enable_usb(void)
{
Assert(CONFIG_USBCLK_DIV > 0);
#ifdef CONFIG_PLL0_SOURCE
if (CONFIG_USBCLK_SOURCE == USBCLK_SRC_PLL0) {
struct pll_config pllcfg;
pll_enable_source(CONFIG_PLL0_SOURCE);
pll_config_defaults(&pllcfg, 0);
pll_enable(&pllcfg, 0);
pll_wait_for_lock(0);
pmc_switch_udpck_to_pllack(CONFIG_USBCLK_DIV - 1);
pmc_enable_udpck();
return;
}
#endif
if (CONFIG_USBCLK_SOURCE == USBCLK_SRC_UPLL) {
pmc_enable_upll_clock();
pmc_switch_udpck_to_upllck(CONFIG_USBCLK_DIV - 1);
pmc_enable_udpck();
return;
}
}
/**
* \brief Disable full speed USB clock.
*
* \note This implementation does not switch off the PLL, it just turns off the USB clock.
*/
void sysclk_disable_usb(void)
{
pmc_disable_udpck();
}
#endif // CONFIG_USBCLK_SOURCE
//! @}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif // ARDUINO_ARCH_SAM

229
src/HAL/DUE/usb/sysclk.h Normal file
View File

@ -0,0 +1,229 @@
/**
* \file
*
* \brief Chip-specific system clock management functions.
*
* Copyright (c) 2011-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef CHIP_SYSCLK_H_INCLUDED
#define CHIP_SYSCLK_H_INCLUDED
#include "osc.h"
#include "pll.h"
/**
* \page sysclk_quickstart Quick Start Guide for the System Clock Management service (SAM3A)
*
* This is the quick start guide for the \ref sysclk_group "System Clock Management"
* service, with step-by-step instructions on how to configure and use the service for
* specific use cases.
*
* \section sysclk_quickstart_usecases System Clock Management use cases
* - \ref sysclk_quickstart_basic
*
* \section sysclk_quickstart_basic Basic usage of the System Clock Management service
* This section will present a basic use case for the System Clock Management service.
* This use case will configure the main system clock to 84MHz, using an internal PLL
* module to multiply the frequency of a crystal attached to the microcontroller.
*
* \subsection sysclk_quickstart_use_case_1_prereq Prerequisites
* - None
*
* \subsection sysclk_quickstart_use_case_1_setup_steps Initialization code
* Add to the application initialization code:
* \code
sysclk_init();
\endcode
*
* \subsection sysclk_quickstart_use_case_1_setup_steps_workflow Workflow
* -# Configure the system clocks according to the settings in conf_clock.h:
* \code sysclk_init(); \endcode
*
* \subsection sysclk_quickstart_use_case_1_example_code Example code
* Add or uncomment the following in your conf_clock.h header file, commenting out all other
* definitions of the same symbol(s):
* \code
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK
// Fpll0 = (Fclk * PLL_mul) / PLL_div
#define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL
#define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL)
#define CONFIG_PLL0_DIV 1
// Fbus = Fsys / BUS_div
#define CONFIG_SYSCLK_PRES SYSCLK_PRES_1
\endcode
*
* \subsection sysclk_quickstart_use_case_1_example_workflow Workflow
* -# Configure the main system clock to use the output of the PLL module as its source:
* \code #define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLLACK \endcode
* -# Configure the PLL module to use the fast external fast crystal oscillator as its source:
* \code #define CONFIG_PLL0_SOURCE PLL_SRC_MAINCK_XTAL \endcode
* -# Configure the PLL module to multiply the external fast crystal oscillator frequency up to 84MHz:
* \code
#define CONFIG_PLL0_MUL (84000000UL / BOARD_FREQ_MAINCK_XTAL)
#define CONFIG_PLL0_DIV 1
\endcode
* \note For user boards, \c BOARD_FREQ_MAINCK_XTAL should be defined in the board \c conf_board.h configuration
* file as the frequency of the fast crystal attached to the microcontroller.
* -# Configure the main clock to run at the full 84MHz, disable scaling of the main system clock speed:
* \code
#define CONFIG_SYSCLK_PRES SYSCLK_PRES_1
\endcode
* \note Some dividers are powers of two, while others are integer division factors. Refer to the
* formulas in the conf_clock.h template commented above each division define.
*/
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
/**
* \weakgroup sysclk_group
* @{
*/
//! \name Configuration Symbols
//@{
/**
* \def CONFIG_SYSCLK_SOURCE
* \brief Initial/static main system clock source
*
* The main system clock will be configured to use this clock during
* initialization.
*/
#ifndef CONFIG_SYSCLK_SOURCE
# define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_MAINCK_4M_RC
#endif
/**
* \def CONFIG_SYSCLK_PRES
* \brief Initial CPU clock divider (mck)
*
* The MCK will run at
* \f[
* f_{MCK} = \frac{f_{sys}}{\mathrm{CONFIG\_SYSCLK\_PRES}}\,\mbox{Hz}
* \f]
* after initialization.
*/
#ifndef CONFIG_SYSCLK_PRES
# define CONFIG_SYSCLK_PRES 0
#endif
//@}
//! \name Master Clock Sources (MCK)
//@{
#define SYSCLK_SRC_SLCK_RC 0 //!< Internal 32kHz RC oscillator as master source clock
#define SYSCLK_SRC_SLCK_XTAL 1 //!< External 32kHz crystal oscillator as master source clock
#define SYSCLK_SRC_SLCK_BYPASS 2 //!< External 32kHz bypass oscillator as master source clock
#define SYSCLK_SRC_MAINCK_4M_RC 3 //!< Internal 4MHz RC oscillator as master source clock
#define SYSCLK_SRC_MAINCK_8M_RC 4 //!< Internal 8MHz RC oscillator as master source clock
#define SYSCLK_SRC_MAINCK_12M_RC 5 //!< Internal 12MHz RC oscillator as master source clock
#define SYSCLK_SRC_MAINCK_XTAL 6 //!< External crystal oscillator as master source clock
#define SYSCLK_SRC_MAINCK_BYPASS 7 //!< External bypass oscillator as master source clock
#define SYSCLK_SRC_PLLACK 8 //!< Use PLLACK as master source clock
#define SYSCLK_SRC_UPLLCK 9 //!< Use UPLLCK as master source clock
//@}
//! \name Master Clock Prescalers (MCK)
//@{
#define SYSCLK_PRES_1 PMC_MCKR_PRES_CLK_1 //!< Set master clock prescaler to 1
#define SYSCLK_PRES_2 PMC_MCKR_PRES_CLK_2 //!< Set master clock prescaler to 2
#define SYSCLK_PRES_4 PMC_MCKR_PRES_CLK_4 //!< Set master clock prescaler to 4
#define SYSCLK_PRES_8 PMC_MCKR_PRES_CLK_8 //!< Set master clock prescaler to 8
#define SYSCLK_PRES_16 PMC_MCKR_PRES_CLK_16 //!< Set master clock prescaler to 16
#define SYSCLK_PRES_32 PMC_MCKR_PRES_CLK_32 //!< Set master clock prescaler to 32
#define SYSCLK_PRES_64 PMC_MCKR_PRES_CLK_64 //!< Set master clock prescaler to 64
#define SYSCLK_PRES_3 PMC_MCKR_PRES_CLK_3 //!< Set master clock prescaler to 3
//@}
//! \name USB Clock Sources
//@{
#define USBCLK_SRC_PLL0 0 //!< Use PLLA
#define USBCLK_SRC_UPLL 1 //!< Use UPLL
//@}
/**
* \def CONFIG_USBCLK_SOURCE
* \brief Configuration symbol for the USB generic clock source
*
* Sets the clock source to use for the USB. The source must also be properly
* configured.
*
* Define this to one of the \c USBCLK_SRC_xxx settings. Leave it undefined if
* USB is not required.
*/
#ifdef __DOXYGEN__
# define CONFIG_USBCLK_SOURCE
#endif
/**
* \def CONFIG_USBCLK_DIV
* \brief Configuration symbol for the USB generic clock divider setting
*
* Sets the clock division for the USB generic clock. If a USB clock source is
* selected with CONFIG_USBCLK_SOURCE, this configuration symbol must also be
* defined.
*/
#ifdef __DOXYGEN__
# define CONFIG_USBCLK_DIV
#endif
extern void sysclk_enable_usb(void);
extern void sysclk_disable_usb(void);
//! @}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* CHIP_SYSCLK_H_INCLUDED */

105
src/HAL/DUE/usb/tpaste.h Normal file
View File

@ -0,0 +1,105 @@
/**
* \file
*
* \brief Preprocessor token pasting utils.
*
* Copyright (c) 2010-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _TPASTE_H_
#define _TPASTE_H_
/**
* \defgroup group_sam_utils_tpaste Preprocessor - Token Paste
*
* \ingroup group_sam_utils
*
* \{
*/
/*! \name Token Paste
*
* Paste N preprocessing tokens together, these tokens being allowed to be \#defined.
*
* May be used only within macros with the tokens passed as arguments if the tokens are \#defined.
*
* For example, writing TPASTE2(U, WIDTH) within a macro \#defined by
* UTYPE(WIDTH) and invoked as UTYPE(UL_WIDTH) with UL_WIDTH \#defined as 32 is
* equivalent to writing U32.
*/
//! @{
#define TPASTE2( a, b) a##b
#define TPASTE3( a, b, c) a##b##c
#define TPASTE4( a, b, c, d) a##b##c##d
#define TPASTE5( a, b, c, d, e) a##b##c##d##e
#define TPASTE6( a, b, c, d, e, f) a##b##c##d##e##f
#define TPASTE7( a, b, c, d, e, f, g) a##b##c##d##e##f##g
#define TPASTE8( a, b, c, d, e, f, g, h) a##b##c##d##e##f##g##h
#define TPASTE9( a, b, c, d, e, f, g, h, i) a##b##c##d##e##f##g##h##i
#define TPASTE10(a, b, c, d, e, f, g, h, i, j) a##b##c##d##e##f##g##h##i##j
//! @}
/*! \name Absolute Token Paste
*
* Paste N preprocessing tokens together, these tokens being allowed to be \#defined.
*
* No restriction of use if the tokens are \#defined.
*
* For example, writing ATPASTE2(U, UL_WIDTH) anywhere with UL_WIDTH \#defined
* as 32 is equivalent to writing U32.
*/
//! @{
#define ATPASTE2( a, b) TPASTE2( a, b)
#define ATPASTE3( a, b, c) TPASTE3( a, b, c)
#define ATPASTE4( a, b, c, d) TPASTE4( a, b, c, d)
#define ATPASTE5( a, b, c, d, e) TPASTE5( a, b, c, d, e)
#define ATPASTE6( a, b, c, d, e, f) TPASTE6( a, b, c, d, e, f)
#define ATPASTE7( a, b, c, d, e, f, g) TPASTE7( a, b, c, d, e, f, g)
#define ATPASTE8( a, b, c, d, e, f, g, h) TPASTE8( a, b, c, d, e, f, g, h)
#define ATPASTE9( a, b, c, d, e, f, g, h, i) TPASTE9( a, b, c, d, e, f, g, h, i)
#define ATPASTE10(a, b, c, d, e, f, g, h, i, j) TPASTE10(a, b, c, d, e, f, g, h, i, j)
//! @}
/**
* \}
*/
#endif // _TPASTE_H_

1149
src/HAL/DUE/usb/udc.c Normal file

File diff suppressed because it is too large Load Diff

697
src/HAL/DUE/usb/udc.h Normal file
View File

@ -0,0 +1,697 @@
/**
* \file
*
* \brief Interface of the USB Device Controller (UDC)
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDC_H_
#define _UDC_H_
#include "conf_usb.h"
#include "usb_protocol.h"
#include "udc_desc.h"
#include "udd.h"
#if USB_DEVICE_VENDOR_ID == 0
# error USB_DEVICE_VENDOR_ID cannot be equal to 0
#endif
#if USB_DEVICE_PRODUCT_ID == 0
# error USB_DEVICE_PRODUCT_ID cannot be equal to 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* \ingroup usb_device_group
* \defgroup udc_group USB Device Controller (UDC)
*
* The UDC provides a high-level abstraction of the usb device.
* You can use these functions to control the main device state
* (start/attach/wakeup).
*
* \section USB_DEVICE_CONF USB Device Custom configuration
* The following USB Device configuration must be included in the conf_usb.h
* file of the application.
*
* USB_DEVICE_VENDOR_ID (Word)<br>
* Vendor ID provided by USB org (ATMEL 0x03EB).
*
* USB_DEVICE_PRODUCT_ID (Word)<br>
* Product ID (Referenced in usb_atmel.h).
*
* USB_DEVICE_MAJOR_VERSION (Byte)<br>
* Major version of the device
*
* USB_DEVICE_MINOR_VERSION (Byte)<br>
* Minor version of the device
*
* USB_DEVICE_MANUFACTURE_NAME (string)<br>
* ASCII name for the manufacture
*
* USB_DEVICE_PRODUCT_NAME (string)<br>
* ASCII name for the product
*
* USB_DEVICE_SERIAL_NAME (string)<br>
* ASCII name to enable and set a serial number
*
* USB_DEVICE_POWER (Numeric)<br>
* (unit mA) Maximum device power
*
* USB_DEVICE_ATTR (Byte)<br>
* USB attributes available:
* - USB_CONFIG_ATTR_SELF_POWERED
* - USB_CONFIG_ATTR_REMOTE_WAKEUP
* Note: if remote wake enabled then defines remotewakeup callbacks,
* see Table 5-2. External API from UDC - Callback
*
* USB_DEVICE_LOW_SPEED (Only defined)<br>
* Force the USB Device to run in low speed
*
* USB_DEVICE_HS_SUPPORT (Only defined)<br>
* Authorize the USB Device to run in high speed
*
* USB_DEVICE_MAX_EP (Byte)<br>
* Define the maximum endpoint number used by the USB Device.<br>
* This one is already defined in UDI default configuration.
* Ex:
* - When endpoint control 0x00, endpoint 0x01 and
* endpoint 0x82 is used then USB_DEVICE_MAX_EP=2
* - When only endpoint control 0x00 is used then USB_DEVICE_MAX_EP=0
* - When endpoint 0x01 and endpoint 0x81 is used then USB_DEVICE_MAX_EP=1<br>
* (configuration not possible on USBB interface)
* @{
*/
/**
* \brief Authorizes the VBUS event
*
* \return true, if the VBUS monitoring is possible.
*
* \section udc_vbus_monitoring VBus monitoring used cases
*
* The VBus monitoring is used only for USB SELF Power application.
*
* - By default the USB device is automatically attached when Vbus is high
* or when USB is start for devices without internal Vbus monitoring.
* conf_usb.h file does not contains define USB_DEVICE_ATTACH_AUTO_DISABLE.
* \code //#define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode
*
* - Add custom VBUS monitoring. conf_usb.h file contains define
* USB_DEVICE_ATTACH_AUTO_DISABLE:
* \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode
* User C file contains:
* \code
// Authorize VBUS monitoring
if (!udc_include_vbus_monitoring()) {
// Implement custom VBUS monitoring via GPIO or other
}
Event_VBUS_present() // VBUS interrupt or GPIO interrupt or other
{
// Attach USB Device
udc_attach();
}
\endcode
*
* - Case of battery charging. conf_usb.h file contains define
* USB_DEVICE_ATTACH_AUTO_DISABLE:
* \code #define USB_DEVICE_ATTACH_AUTO_DISABLE \endcode
* User C file contains:
* \code
Event VBUS present() // VBUS interrupt or GPIO interrupt or ..
{
// Authorize battery charging, but wait key press to start USB.
}
Event Key press()
{
// Stop batteries charging
// Start USB
udc_attach();
}
\endcode
*/
static inline bool udc_include_vbus_monitoring(void)
{
return udd_include_vbus_monitoring();
}
/*! \brief Start the USB Device stack
*/
void udc_start(void);
/*! \brief Stop the USB Device stack
*/
void udc_stop(void);
/**
* \brief Attach device to the bus when possible
*
* \warning If a VBus control is included in driver,
* then it will attach device when an acceptable Vbus
* level from the host is detected.
*/
static inline void udc_attach(void)
{
udd_attach();
}
/**
* \brief Detaches the device from the bus
*
* The driver must remove pull-up on USB line D- or D+.
*/
static inline void udc_detach(void)
{
udd_detach();
}
/*! \brief The USB driver sends a resume signal called \e "Upstream Resume"
* This is authorized only when the remote wakeup feature is enabled by host.
*/
static inline void udc_remotewakeup(void)
{
udd_send_remotewakeup();
}
/**
* \brief Returns a pointer on the current interface descriptor
*
* \return pointer on the current interface descriptor.
*/
usb_iface_desc_t UDC_DESC_STORAGE *udc_get_interface_desc(void);
//@}
/**
* \ingroup usb_group
* \defgroup usb_device_group USB Stack Device
*
* This module includes USB Stack Device implementation.
* The stack is divided in three parts:
* - USB Device Controller (UDC) provides USB chapter 9 compliance
* - USB Device Interface (UDI) provides USB Class compliance
* - USB Device Driver (UDD) provides USB Driver for each Atmel MCU
* Many USB Device applications can be implemented on Atmel MCU.
* Atmel provides many application notes for different applications:
* - AVR4900, provides general information about Device Stack
* - AVR4901, explains how to create a new class
* - AVR4902, explains how to create a composite device
* - AVR49xx, all device classes provided in ASF have an application note
*
* A basic USB knowledge is required to understand the USB Device
* Class application notes (HID,MS,CDC,PHDC,...).
* Then, to create an USB device with
* only one class provided by ASF, refer directly to the application note
* corresponding to this USB class. The USB Device application note for
* New Class and Composite is dedicated to advanced USB users.
*
* @{
*/
//! @}
#ifdef __cplusplus
}
#endif
/**
* \ingroup udc_group
* \defgroup udc_basic_use_case_setup_prereq USB Device Controller (UDC) - Prerequisites
* Common prerequisites for all USB devices.
*
* This module is based on USB device stack full interrupt driven, and supporting
* \ref sleepmgr_group sleepmgr. For AVR and SAM3/4 devices the \ref clk_group clock services
* is supported. For SAMD devices the \ref asfdoc_sam0_system_clock_group clock driver is supported.
*
* The following procedure must be executed to setup the project correctly:
* - Specify the clock configuration:
* - XMEGA USB devices need 48MHz clock input.\n
* XMEGA USB devices need CPU frequency higher than 12MHz.\n
* You can use either an internal RC48MHz auto calibrated by Start of Frames
* or an external OSC.
* - UC3 and SAM3/4 devices without USB high speed support need 48MHz clock input.\n
* You must use a PLL and an external OSC.
* - UC3 and SAM3/4 devices with USB high speed support need 12MHz clock input.\n
* You must use an external OSC.
* - UC3 devices with USBC hardware need CPU frequency higher than 25MHz.
* - SAMD devices without USB high speed support need 48MHz clock input.\n
* You should use DFLL with USBCRM.
* - In conf_board.h, the define CONF_BOARD_USB_PORT must be added to enable USB lines.
* (Not mandatory for all boards)
* - Enable interrupts
* - Initialize the clock service
*
* The usage of \ref sleepmgr_group sleepmgr service is optional, but recommended to reduce power
* consumption:
* - Initialize the sleep manager service
* - Activate sleep mode when the application is in IDLE state
*
* \subpage udc_conf_clock.
*
* for AVR and SAM3/4 devices, add to the initialization code:
* \code
sysclk_init();
irq_initialize_vectors();
cpu_irq_enable();
board_init();
sleepmgr_init(); // Optional
\endcode
*
* For SAMD devices, add to the initialization code:
* \code
system_init();
irq_initialize_vectors();
cpu_irq_enable();
sleepmgr_init(); // Optional
\endcode
* Add to the main IDLE loop:
* \code
sleepmgr_enter_sleep(); // Optional
\endcode
*
*/
/**
* \ingroup udc_group
* \defgroup udc_basic_use_case_setup_code USB Device Controller (UDC) - Example code
* Common example code for all USB devices.
*
* Content of conf_usb.h:
* \code
#define USB_DEVICE_VENDOR_ID 0x03EB
#define USB_DEVICE_PRODUCT_ID 0xXXXX
#define USB_DEVICE_MAJOR_VERSION 1
#define USB_DEVICE_MINOR_VERSION 0
#define USB_DEVICE_POWER 100
#define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED
\endcode
*
* Add to application C-file:
* \code
void usb_init(void)
{
udc_start();
}
\endcode
*/
/**
* \ingroup udc_group
* \defgroup udc_basic_use_case_setup_flow USB Device Controller (UDC) - Workflow
* Common workflow for all USB devices.
*
* -# Ensure that conf_usb.h is available and contains the following configuration
* which is the main USB device configuration:
* - \code // Vendor ID provided by USB org (ATMEL 0x03EB)
#define USB_DEVICE_VENDOR_ID 0x03EB // Type Word
// Product ID (Atmel PID referenced in usb_atmel.h)
#define USB_DEVICE_PRODUCT_ID 0xXXXX // Type Word
// Major version of the device
#define USB_DEVICE_MAJOR_VERSION 1 // Type Byte
// Minor version of the device
#define USB_DEVICE_MINOR_VERSION 0 // Type Byte
// Maximum device power (mA)
#define USB_DEVICE_POWER 100 // Type 9-bits
// USB attributes to enable features
#define USB_DEVICE_ATTR USB_CONFIG_ATTR_BUS_POWERED // Flags \endcode
* -# Call the USB device stack start function to enable stack and start USB:
* - \code udc_start(); \endcode
* \note In case of USB dual roles (Device and Host) managed through USB OTG connector
* (USB ID pin), the call of udc_start() must be removed and replaced by uhc_start().
* SeRefer to "AVR4950 section 6.1 Dual roles" for further information about dual roles.
*/
/**
* \page udc_conf_clock conf_clock.h examples with USB support
*
* Content of XMEGA conf_clock.h:
* \code
// Configuration based on internal RC:
// USB clock need of 48Mhz
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_RCOSC
#define CONFIG_OSC_RC32_CAL 48000000UL
#define CONFIG_OSC_AUTOCAL_RC32MHZ_REF_OSC OSC_ID_USBSOF
// CPU clock need of clock > 12MHz to run with USB (Here 24MHz)
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_RC32MHZ
#define CONFIG_SYSCLK_PSADIV SYSCLK_PSADIV_2
#define CONFIG_SYSCLK_PSBCDIV SYSCLK_PSBCDIV_1_1
\endcode
*
* Content of conf_clock.h for AT32UC3A0, AT32UC3A1, AT32UC3B devices (USBB):
* \code
// Configuration based on 12MHz external OSC:
#define CONFIG_PLL1_SOURCE PLL_SRC_OSC0
#define CONFIG_PLL1_MUL 8
#define CONFIG_PLL1_DIV 2
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1
#define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div)
\endcode
*
* Content of conf_clock.h for AT32UC3A3, AT32UC3A4 devices (USBB with high speed support):
* \code
// Configuration based on 12MHz external OSC:
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_OSC0
#define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div)
\endcode
*
* Content of conf_clock.h for AT32UC3C, ATUCXXD, ATUCXXL3U, ATUCXXL4U devices (USBC):
* \code
// Configuration based on 12MHz external OSC:
#define CONFIG_PLL1_SOURCE PLL_SRC_OSC0
#define CONFIG_PLL1_MUL 8
#define CONFIG_PLL1_DIV 2
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1
#define CONFIG_USBCLK_DIV 1 // Fusb = Fsys/(2 ^ USB_div)
// CPU clock need of clock > 25MHz to run with USBC
#define CONFIG_SYSCLK_SOURCE SYSCLK_SRC_PLL1
\endcode
*
* Content of conf_clock.h for SAM3S, SAM3SD, SAM4S devices (UPD: USB Peripheral Device):
* \code
// PLL1 (B) Options (Fpll = (Fclk * PLL_mul) / PLL_div)
#define CONFIG_PLL1_SOURCE PLL_SRC_MAINCK_XTAL
#define CONFIG_PLL1_MUL 16
#define CONFIG_PLL1_DIV 2
// USB Clock Source Options (Fusb = FpllX / USB_div)
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_PLL1
#define CONFIG_USBCLK_DIV 2
\endcode
*
* Content of conf_clock.h for SAM3U device (UPDHS: USB Peripheral Device High Speed):
* \code
// USB Clock Source fixed at UPLL.
\endcode
*
* Content of conf_clock.h for SAM3X, SAM3A devices (UOTGHS: USB OTG High Speed):
* \code
// USB Clock Source fixed at UPLL.
#define CONFIG_USBCLK_SOURCE USBCLK_SRC_UPLL
#define CONFIG_USBCLK_DIV 1
\endcode
*
* Content of conf_clocks.h for SAMD devices (USB):
* \code
// System clock bus configuration
# define CONF_CLOCK_FLASH_WAIT_STATES 2
// USB Clock Source fixed at DFLL.
// SYSTEM_CLOCK_SOURCE_DFLL configuration - Digital Frequency Locked Loop
# define CONF_CLOCK_DFLL_ENABLE true
# define CONF_CLOCK_DFLL_LOOP_MODE SYSTEM_CLOCK_DFLL_LOOP_MODE_USB_RECOVERY
# define CONF_CLOCK_DFLL_ON_DEMAND true
// Set this to true to configure the GCLK when running clocks_init.
// If set to false, none of the GCLK generators will be configured in clocks_init().
# define CONF_CLOCK_CONFIGURE_GCLK true
// Configure GCLK generator 0 (Main Clock)
# define CONF_CLOCK_GCLK_0_ENABLE true
# define CONF_CLOCK_GCLK_0_RUN_IN_STANDBY true
# define CONF_CLOCK_GCLK_0_CLOCK_SOURCE SYSTEM_CLOCK_SOURCE_DFLL
# define CONF_CLOCK_GCLK_0_PRESCALER 1
# define CONF_CLOCK_GCLK_0_OUTPUT_ENABLE false
\endcode
*/
/**
* \page udc_use_case_1 Change USB speed
*
* In this use case, the USB device is used with different USB speeds.
*
* \section udc_use_case_1_setup Setup steps
*
* Prior to implement this use case, be sure to have already
* apply the UDI module "basic use case".
*
* \section udc_use_case_1_usage Usage steps
*
* \subsection udc_use_case_1_usage_code Example code
* Content of conf_usb.h:
* \code
#if // Low speed
#define USB_DEVICE_LOW_SPEED
// #define USB_DEVICE_HS_SUPPORT
#elif // Full speed
// #define USB_DEVICE_LOW_SPEED
// #define USB_DEVICE_HS_SUPPORT
#elif // High speed
// #define USB_DEVICE_LOW_SPEED
#define USB_DEVICE_HS_SUPPORT
#endif
\endcode
*
* \subsection udc_use_case_1_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters
* required for a USB device low speed (1.5Mbit/s):
* - \code #define USB_DEVICE_LOW_SPEED
//#define USB_DEVICE_HS_SUPPORT \endcode
* -# Ensure that conf_usb.h contains the following parameters
* required for a USB device full speed (12Mbit/s):
* - \code //#define USB_DEVICE_LOW_SPEED
//#define USB_DEVICE_HS_SUPPORT \endcode
* -# Ensure that conf_usb.h contains the following parameters
* required for a USB device high speed (480Mbit/s):
* - \code //#define USB_DEVICE_LOW_SPEED
#define USB_DEVICE_HS_SUPPORT \endcode
*/
/**
* \page udc_use_case_2 Use USB strings
*
* In this use case, the usual USB strings is added in the USB device.
*
* \section udc_use_case_2_setup Setup steps
* Prior to implement this use case, be sure to have already
* apply the UDI module "basic use case".
*
* \section udc_use_case_2_usage Usage steps
*
* \subsection udc_use_case_2_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_MANUFACTURE_NAME "Manufacture name"
#define USB_DEVICE_PRODUCT_NAME "Product name"
#define USB_DEVICE_SERIAL_NAME "12...EF"
\endcode
*
* \subsection udc_use_case_2_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters
* required to enable different USB strings:
* - \code // Static ASCII name for the manufacture
#define USB_DEVICE_MANUFACTURE_NAME "Manufacture name" \endcode
* - \code // Static ASCII name for the product
#define USB_DEVICE_PRODUCT_NAME "Product name" \endcode
* - \code // Static ASCII name to enable and set a serial number
#define USB_DEVICE_SERIAL_NAME "12...EF" \endcode
*/
/**
* \page udc_use_case_3 Use USB remote wakeup feature
*
* In this use case, the USB remote wakeup feature is enabled.
*
* \section udc_use_case_3_setup Setup steps
* Prior to implement this use case, be sure to have already
* apply the UDI module "basic use case".
*
* \section udc_use_case_3_usage Usage steps
*
* \subsection udc_use_case_3_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_ATTR \
(USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED)
#define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable()
extern void my_callback_remotewakeup_enable(void);
#define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable()
extern void my_callback_remotewakeup_disable(void);
\endcode
*
* Add to application C-file:
* \code
void my_callback_remotewakeup_enable(void)
{
// Enable application wakeup events (e.g. enable GPIO interrupt)
}
void my_callback_remotewakeup_disable(void)
{
// Disable application wakeup events (e.g. disable GPIO interrupt)
}
void my_interrupt_event(void)
{
udc_remotewakeup();
}
\endcode
*
* \subsection udc_use_case_3_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters
* required to enable remote wakeup feature:
* - \code // Authorizes the remote wakeup feature
#define USB_DEVICE_ATTR (USB_CONFIG_ATTR_REMOTE_WAKEUP | USB_CONFIG_ATTR_..._POWERED) \endcode
* - \code // Define callback called when the host enables the remotewakeup feature
#define UDC_REMOTEWAKEUP_ENABLE() my_callback_remotewakeup_enable()
extern void my_callback_remotewakeup_enable(void); \endcode
* - \code // Define callback called when the host disables the remotewakeup feature
#define UDC_REMOTEWAKEUP_DISABLE() my_callback_remotewakeup_disable()
extern void my_callback_remotewakeup_disable(void); \endcode
* -# Send a remote wakeup (USB upstream):
* - \code udc_remotewakeup(); \endcode
*/
/**
* \page udc_use_case_5 Bus power application recommendations
*
* In this use case, the USB device BUS power feature is enabled.
* This feature requires a correct power consumption management.
*
* \section udc_use_case_5_setup Setup steps
* Prior to implement this use case, be sure to have already
* apply the UDI module "basic use case".
*
* \section udc_use_case_5_usage Usage steps
*
* \subsection udc_use_case_5_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED)
#define UDC_SUSPEND_EVENT() user_callback_suspend_action()
extern void user_callback_suspend_action(void)
#define UDC_RESUME_EVENT() user_callback_resume_action()
extern void user_callback_resume_action(void)
\endcode
*
* Add to application C-file:
* \code
void user_callback_suspend_action(void)
{
// Disable hardware component to reduce power consumption
}
void user_callback_resume_action(void)
{
// Re-enable hardware component
}
\endcode
*
* \subsection udc_use_case_5_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters:
* - \code // Authorizes the BUS power feature
#define USB_DEVICE_ATTR (USB_CONFIG_ATTR_BUS_POWERED) \endcode
* - \code // Define callback called when the host suspend the USB line
#define UDC_SUSPEND_EVENT() user_callback_suspend_action()
extern void user_callback_suspend_action(void); \endcode
* - \code // Define callback called when the host or device resume the USB line
#define UDC_RESUME_EVENT() user_callback_resume_action()
extern void user_callback_resume_action(void); \endcode
* -# Reduce power consumption in suspend mode (max. 2.5mA on Vbus):
* - \code void user_callback_suspend_action(void)
{
turn_off_components();
} \endcode
*/
/**
* \page udc_use_case_6 USB dynamic serial number
*
* In this use case, the USB serial strings is dynamic.
* For a static serial string refer to \ref udc_use_case_2.
*
* \section udc_use_case_6_setup Setup steps
* Prior to implement this use case, be sure to have already
* apply the UDI module "basic use case".
*
* \section udc_use_case_6_usage Usage steps
*
* \subsection udc_use_case_6_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_SERIAL_NAME
#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number
#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12
extern uint8_t serial_number[];
\endcode
*
* Add to application C-file:
* \code
uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
void init_build_usb_serial_number(void)
{
serial_number[0] = 'A';
serial_number[1] = 'B';
...
serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C';
} \endcode
*
* \subsection udc_use_case_6_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters
* required to enable a USB serial number strings dynamically:
* - \code #define USB_DEVICE_SERIAL_NAME // Define this empty
#define USB_DEVICE_GET_SERIAL_NAME_POINTER serial_number // Give serial array pointer
#define USB_DEVICE_GET_SERIAL_NAME_LENGTH 12 // Give size of serial array
extern uint8_t serial_number[]; // Declare external serial array \endcode
* -# Before start USB stack, initialize the serial array
* - \code
uint8_t serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH];
void init_build_usb_serial_number(void)
{
serial_number[0] = 'A';
serial_number[1] = 'B';
...
serial_number[USB_DEVICE_GET_SERIAL_NAME_LENGTH-1] = 'C';
} \endcode
*/
#endif // _UDC_H_

135
src/HAL/DUE/usb/udc_desc.h Normal file
View File

@ -0,0 +1,135 @@
/**
* \file
*
* \brief Common API for USB Device Interface
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDC_DESC_H_
#define _UDC_DESC_H_
#include "conf_usb.h"
#include "usb_protocol.h"
#include "udi.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \ingroup udc_group
* \defgroup udc_desc_group USB Device Descriptor
*
* @{
*/
/**
* \brief Defines the memory's location of USB descriptors
*
* By default the Descriptor is stored in RAM
* (UDC_DESC_STORAGE is defined empty).
*
* If you have need to free RAM space,
* it is possible to put descriptor in flash in following case:
* - USB driver authorize flash transfer (USBB on UC3 and USB on Mega)
* - USB Device is not high speed (UDC no need to change USB descriptors)
*
* For UC3 application used "const".
*
* For Mega application used "code".
*/
#define UDC_DESC_STORAGE
// Descriptor storage in internal RAM
#if (defined UDC_DATA_USE_HRAM_SUPPORT)
# if defined(__GNUC__)
# define UDC_DATA(x) COMPILER_WORD_ALIGNED __attribute__((__section__(".data_hram0")))
# define UDC_BSS(x) COMPILER_ALIGNED(x) __attribute__((__section__(".bss_hram0")))
# elif defined(__ICCAVR32__)
# define UDC_DATA(x) COMPILER_ALIGNED(x) __data32
# define UDC_BSS(x) COMPILER_ALIGNED(x) __data32
# endif
#else
# define UDC_DATA(x) COMPILER_ALIGNED(x)
# define UDC_BSS(x) COMPILER_ALIGNED(x)
#endif
/**
* \brief Configuration descriptor and UDI link for one USB speed
*/
typedef struct {
//! USB configuration descriptor
usb_conf_desc_t UDC_DESC_STORAGE *desc;
//! Array of UDI API pointer
udi_api_t UDC_DESC_STORAGE *UDC_DESC_STORAGE * udi_apis;
} udc_config_speed_t;
/**
* \brief All information about the USB Device
*/
typedef struct {
//! USB device descriptor for low or full speed
usb_dev_desc_t UDC_DESC_STORAGE *confdev_lsfs;
//! USB configuration descriptor and UDI API pointers for low or full speed
udc_config_speed_t UDC_DESC_STORAGE *conf_lsfs;
#ifdef USB_DEVICE_HS_SUPPORT
//! USB device descriptor for high speed
usb_dev_desc_t UDC_DESC_STORAGE *confdev_hs;
//! USB device qualifier, only use in high speed mode
usb_dev_qual_desc_t UDC_DESC_STORAGE *qualifier;
//! USB configuration descriptor and UDI API pointers for high speed
udc_config_speed_t UDC_DESC_STORAGE *conf_hs;
#endif
usb_dev_bos_desc_t UDC_DESC_STORAGE *conf_bos;
} udc_config_t;
//! Global variables of USB Device Descriptor and UDI links
extern UDC_DESC_STORAGE udc_config_t udc_config;
//@}
#ifdef __cplusplus
}
#endif
#endif // _UDC_DESC_H_

396
src/HAL/DUE/usb/udd.h Normal file
View File

@ -0,0 +1,396 @@
/**
* \file
*
* \brief Common API for USB Device Drivers (UDD)
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDD_H_
#define _UDD_H_
#include "usb_protocol.h"
#include "udc_desc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \ingroup usb_device_group
* \defgroup udd_group USB Device Driver (UDD)
*
* The UDD driver provides a low-level abstraction of the device
* controller hardware. Most events coming from the hardware such as
* interrupts, which may cause the UDD to call into the UDC and UDI.
*
* @{
*/
//! \brief Endpoint identifier
typedef uint8_t udd_ep_id_t;
//! \brief Endpoint transfer status
//! Returned in parameters of callback register via udd_ep_run routine.
typedef enum {
UDD_EP_TRANSFER_OK = 0,
UDD_EP_TRANSFER_ABORT = 1,
} udd_ep_status_t;
/**
* \brief Global variable to give and record information of the setup request management
*
* This global variable allows to decode and response a setup request.
* It can be updated by udc_process_setup() from UDC or *setup() from UDIs.
*/
typedef struct {
//! Data received in USB SETUP packet
//! Note: The swap of "req.wValues" from uin16_t to le16_t is done by UDD.
usb_setup_req_t req;
//! Point to buffer to send or fill with data following SETUP packet
//! This buffer must be word align for DATA IN phase (use prefix COMPILER_WORD_ALIGNED for buffer)
uint8_t *payload;
//! Size of buffer to send or fill, and content the number of byte transferred
uint16_t payload_size;
//! Callback called after reception of ZLP from setup request
void (*callback)(void);
//! Callback called when the buffer given (.payload) is full or empty.
//! This one return false to abort data transfer, or true with a new buffer in .payload.
bool (*over_under_run)(void);
} udd_ctrl_request_t;
extern udd_ctrl_request_t udd_g_ctrlreq;
//! Return true if the setup request \a udd_g_ctrlreq indicates IN data transfer
#define Udd_setup_is_in() \
(USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK))
//! Return true if the setup request \a udd_g_ctrlreq indicates OUT data transfer
#define Udd_setup_is_out() \
(USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK))
//! Return the type of the SETUP request \a udd_g_ctrlreq. \see usb_reqtype.
#define Udd_setup_type() \
(udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK)
//! Return the recipient of the SETUP request \a udd_g_ctrlreq. \see usb_recipient
#define Udd_setup_recipient() \
(udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK)
/**
* \brief End of halt callback function type.
* Registered by routine udd_ep_wait_stall_clear()
* Callback called when endpoint stall is cleared.
*/
typedef void (*udd_callback_halt_cleared_t)(void);
/**
* \brief End of transfer callback function type.
* Registered by routine udd_ep_run()
* Callback called by USB interrupt after data transfer or abort (reset,...).
*
* \param status UDD_EP_TRANSFER_OK, if transfer is complete
* \param status UDD_EP_TRANSFER_ABORT, if transfer is aborted
* \param n number of data transferred
*/
typedef void (*udd_callback_trans_t) (udd_ep_status_t status,
iram_size_t nb_transferred, udd_ep_id_t ep);
/**
* \brief Authorizes the VBUS event
*
* \return true, if the VBUS monitoring is possible.
*/
bool udd_include_vbus_monitoring(void);
/**
* \brief Enables the USB Device mode
*/
void udd_enable(void);
/**
* \brief Disables the USB Device mode
*/
void udd_disable(void);
/**
* \brief Attach device to the bus when possible
*
* \warning If a VBus control is included in driver,
* then it will attach device when an acceptable Vbus
* level from the host is detected.
*/
void udd_attach(void);
/**
* \brief Detaches the device from the bus
*
* The driver must remove pull-up on USB line D- or D+.
*/
void udd_detach(void);
/**
* \brief Test whether the USB Device Controller is running at high
* speed or not.
*
* \return \c true if the Device is running at high speed mode, otherwise \c false.
*/
bool udd_is_high_speed(void);
/**
* \brief Changes the USB address of device
*
* \param address New USB address
*/
void udd_set_address(uint8_t address);
/**
* \brief Returns the USB address of device
*
* \return USB address
*/
uint8_t udd_getaddress(void);
/**
* \brief Returns the current start of frame number
*
* \return current start of frame number.
*/
uint16_t udd_get_frame_number(void);
/**
* \brief Returns the current micro start of frame number
*
* \return current micro start of frame number required in high speed mode.
*/
uint16_t udd_get_micro_frame_number(void);
/*! \brief The USB driver sends a resume signal called Upstream Resume
*/
void udd_send_remotewakeup(void);
/**
* \brief Load setup payload
*
* \param payload Pointer on payload
* \param payload_size Size of payload
*/
void udd_set_setup_payload( uint8_t *payload, uint16_t payload_size );
/**
* \name Endpoint Management
*
* The following functions allow drivers to create and remove
* endpoints, as well as set, clear and query their "halted" and
* "wedged" states.
*/
//@{
#if (USB_DEVICE_MAX_EP != 0)
/**
* \brief Configures and enables an endpoint
*
* \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT).
* \param bmAttributes Attributes of endpoint declared in the descriptor.
* \param MaxEndpointSize Endpoint maximum size
*
* \return \c 1 if the endpoint is enabled, otherwise \c 0.
*/
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes,
uint16_t MaxEndpointSize);
/**
* \brief Disables an endpoint
*
* \param ep Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT).
*/
void udd_ep_free(udd_ep_id_t ep);
/**
* \brief Check if the endpoint \a ep is halted.
*
* \param ep The ID of the endpoint to check.
*
* \return \c 1 if \a ep is halted, otherwise \c 0.
*/
bool udd_ep_is_halted(udd_ep_id_t ep);
/**
* \brief Set the halted state of the endpoint \a ep
*
* After calling this function, any transaction on \a ep will result
* in a STALL handshake being sent. Any pending transactions will be
* performed first, however.
*
* \param ep The ID of the endpoint to be halted
*
* \return \c 1 if \a ep is halted, otherwise \c 0.
*/
bool udd_ep_set_halt(udd_ep_id_t ep);
/**
* \brief Clear the halted state of the endpoint \a ep
*
* After calling this function, any transaction on \a ep will
* be handled normally, i.e. a STALL handshake will not be sent, and
* the data toggle sequence will start at DATA0.
*
* \param ep The ID of the endpoint to be un-halted
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
bool udd_ep_clear_halt(udd_ep_id_t ep);
/**
* \brief Registers a callback to call when endpoint halt is cleared
*
* \param ep The ID of the endpoint to use
* \param callback NULL or function to call when endpoint halt is cleared
*
* \warning if the endpoint is not halted then the \a callback is called immediately.
*
* \return \c 1 if the register is accepted, otherwise \c 0.
*/
bool udd_ep_wait_stall_clear(udd_ep_id_t ep,
udd_callback_halt_cleared_t callback);
/**
* \brief Allows to receive or send data on an endpoint
*
* The driver uses a specific DMA USB to transfer data
* from internal RAM to endpoint, if this one is available.
* When the transfer is finished or aborted (stall, reset, ...), the \a callback is called.
* The \a callback returns the transfer status and eventually the number of byte transferred.
* Note: The control endpoint is not authorized.
*
* \param ep The ID of the endpoint to use
* \param b_shortpacket Enabled automatic short packet
* \param buf Buffer on Internal RAM to send or fill.
* It must be align, then use COMPILER_WORD_ALIGNED.
* \param buf_size Buffer size to send or fill
* \param callback NULL or function to call at the end of transfer
*
* \warning About \a b_shortpacket, for IN endpoint it means that a short packet
* (or a Zero Length Packet) will be sent to the USB line to properly close the usb
* transfer at the end of the data transfer.
* For Bulk and Interrupt OUT endpoint, it will automatically stop the transfer
* at the end of the data transfer (received short packet).
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket,
uint8_t * buf, iram_size_t buf_size,
udd_callback_trans_t callback);
/**
* \brief Aborts transfer on going on endpoint
*
* If a transfer is on going, then it is stopped and
* the callback registered is called to signal the end of transfer.
* Note: The control endpoint is not authorized.
*
* \param ep Endpoint to abort
*/
void udd_ep_abort(udd_ep_id_t ep);
#endif
//@}
/**
* \name High speed test mode management
*
* The following functions allow the device to jump to a specific test mode required in high speed mode.
*/
//@{
void udd_test_mode_j(void);
void udd_test_mode_k(void);
void udd_test_mode_se0_nak(void);
void udd_test_mode_packet(void);
//@}
/**
* \name UDC callbacks to provide for UDD
*
* The following callbacks are used by UDD.
*/
//@{
/**
* \brief Decodes and manages a setup request
*
* The driver call it when a SETUP packet is received.
* The \c udd_g_ctrlreq contains the data of SETUP packet.
* If this callback accepts the setup request then it must
* return \c 1 and eventually update \c udd_g_ctrlreq to send or receive data.
*
* \return \c 1 if the request is accepted, otherwise \c 0.
*/
extern bool udc_process_setup(void);
/**
* \brief Reset the UDC
*
* The UDC must reset all configuration.
*/
extern void udc_reset(void);
/**
* \brief To signal that a SOF is occurred
*
* The UDC must send the signal to all UDIs enabled
*/
extern void udc_sof_notify(void);
//@}
//@}
#ifdef __cplusplus
}
#endif
#endif // _UDD_H_

133
src/HAL/DUE/usb/udi.h Normal file
View File

@ -0,0 +1,133 @@
/**
* \file
*
* \brief Common API for USB Device Interface
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDI_H_
#define _UDI_H_
#include "conf_usb.h"
#include "usb_protocol.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \ingroup usb_device_group
* \defgroup udi_group USB Device Interface (UDI)
* The UDI provides a common API for all classes,
* and this is used by UDC for the main control of USB Device interface.
* @{
*/
/**
* \brief UDI API.
*
* The callbacks within this structure are called only by
* USB Device Controller (UDC)
*
* The udc_get_interface_desc() can be use by UDI to know the interface descriptor
* selected by UDC.
*/
typedef struct {
/**
* \brief Enable the interface.
*
* This function is called when the host selects a configuration
* to which this interface belongs through a Set Configuration
* request, and when the host selects an alternate setting of
* this interface through a Set Interface request.
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
bool (*enable)(void);
/**
* \brief Disable the interface.
*
* This function is called when this interface is currently
* active, and
* - the host selects any configuration through a Set
* Configuration request, or
* - the host issues a USB reset, or
* - the device is detached from the host (i.e. Vbus is no
* longer present)
*/
void (*disable)(void);
/**
* \brief Handle a control request directed at an interface.
*
* This function is called when this interface is currently
* active and the host sends a SETUP request
* with this interface as the recipient.
*
* Use udd_g_ctrlreq to decode and response to SETUP request.
*
* \return \c 1 if this interface supports the SETUP request, otherwise \c 0.
*/
bool (*setup)(void);
/**
* \brief Returns the current setting of the selected interface.
*
* This function is called when UDC when know alternate setting of selected interface.
*
* \return alternate setting of selected interface
*/
uint8_t (*getsetting)(void);
/**
* \brief To signal that a SOF is occurred
*/
void (*sof_notify)(void);
} udi_api_t;
//@}
#ifdef __cplusplus
}
#endif
#endif // _UDI_H_

1155
src/HAL/DUE/usb/udi_cdc.c Normal file

File diff suppressed because it is too large Load Diff

810
src/HAL/DUE/usb/udi_cdc.h Normal file
View File

@ -0,0 +1,810 @@
/**
* \file
*
* \brief USB Device Communication Device Class (CDC) interface definitions.
*
* Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDI_CDC_H_
#define _UDI_CDC_H_
#include "conf_usb.h"
#include "usb_protocol.h"
#include "usb_protocol_cdc.h"
#include "udd.h"
#include "udc_desc.h"
#include "udi.h"
// Check the number of port
#ifndef UDI_CDC_PORT_NB
# define UDI_CDC_PORT_NB 1
#endif
#if (UDI_CDC_PORT_NB < 1) || (UDI_CDC_PORT_NB > 7)
# error UDI_CDC_PORT_NB must be between 1 and 7
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup udi_cdc_group_udc
* @{
*/
//! Global structure which contains standard UDI API for UDC
extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_comm;
extern UDC_DESC_STORAGE udi_api_t udi_api_cdc_data;
//@}
/**
* \ingroup udi_cdc_group
* \defgroup udi_cdc_group_desc USB interface descriptors
*
* The following structures provide predefined USB interface descriptors.
* It must be used to define the final USB descriptors.
*/
//@{
/**
* \brief Communication Class interface descriptor
*
* Interface descriptor with associated functional and endpoint
* descriptors for the CDC Communication Class interface.
*/
typedef struct {
//! Standard interface descriptor
usb_iface_desc_t iface;
//! CDC Header functional descriptor
usb_cdc_hdr_desc_t header;
//! CDC Abstract Control Model functional descriptor
usb_cdc_acm_desc_t acm;
//! CDC Union functional descriptor
usb_cdc_union_desc_t union_desc;
//! CDC Call Management functional descriptor
usb_cdc_call_mgmt_desc_t call_mgmt;
//! Notification endpoint descriptor
usb_ep_desc_t ep_notify;
} udi_cdc_comm_desc_t;
/**
* \brief Data Class interface descriptor
*
* Interface descriptor with associated endpoint descriptors for the
* CDC Data Class interface.
*/
typedef struct {
//! Standard interface descriptor
usb_iface_desc_t iface;
//! Data IN/OUT endpoint descriptors
usb_ep_desc_t ep_in;
usb_ep_desc_t ep_out;
} udi_cdc_data_desc_t;
//! CDC communication endpoints size for all speeds
#define UDI_CDC_COMM_EP_SIZE 64
//! CDC data endpoints size for FS speed (8B, 16B, 32B, 64B)
#define UDI_CDC_DATA_EPS_FS_SIZE 64
//! CDC data endpoints size for HS speed (512B only)
#define UDI_CDC_DATA_EPS_HS_SIZE 512
/**
* \name Content of interface descriptors
* Up to 7 CDC interfaces can be implemented on a USB device.
*/
//@{
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_0
#define UDI_CDC_IAD_STRING_ID_0 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_0
#define UDI_CDC_COMM_STRING_ID_0 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_0
#define UDI_CDC_DATA_STRING_ID_0 0
#endif
#define UDI_CDC_IAD_DESC_0 UDI_CDC_IAD_DESC(0)
#define UDI_CDC_COMM_DESC_0 UDI_CDC_COMM_DESC(0)
#define UDI_CDC_DATA_DESC_0_FS UDI_CDC_DATA_DESC_FS(0)
#define UDI_CDC_DATA_DESC_0_HS UDI_CDC_DATA_DESC_HS(0)
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_1
#define UDI_CDC_IAD_STRING_ID_1 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_1
#define UDI_CDC_COMM_STRING_ID_1 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_1
#define UDI_CDC_DATA_STRING_ID_1 0
#endif
#define UDI_CDC_IAD_DESC_1 UDI_CDC_IAD_DESC(1)
#define UDI_CDC_COMM_DESC_1 UDI_CDC_COMM_DESC(1)
#define UDI_CDC_DATA_DESC_1_FS UDI_CDC_DATA_DESC_FS(1)
#define UDI_CDC_DATA_DESC_1_HS UDI_CDC_DATA_DESC_HS(1)
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_2
#define UDI_CDC_IAD_STRING_ID_2 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_2
#define UDI_CDC_COMM_STRING_ID_2 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_2
#define UDI_CDC_DATA_STRING_ID_2 0
#endif
#define UDI_CDC_IAD_DESC_2 UDI_CDC_IAD_DESC(2)
#define UDI_CDC_COMM_DESC_2 UDI_CDC_COMM_DESC(2)
#define UDI_CDC_DATA_DESC_2_FS UDI_CDC_DATA_DESC_FS(2)
#define UDI_CDC_DATA_DESC_2_HS UDI_CDC_DATA_DESC_HS(2)
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_3
#define UDI_CDC_IAD_STRING_ID_3 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_3
#define UDI_CDC_COMM_STRING_ID_3 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_3
#define UDI_CDC_DATA_STRING_ID_3 0
#endif
#define UDI_CDC_IAD_DESC_3 UDI_CDC_IAD_DESC(3)
#define UDI_CDC_COMM_DESC_3 UDI_CDC_COMM_DESC(3)
#define UDI_CDC_DATA_DESC_3_FS UDI_CDC_DATA_DESC_FS(3)
#define UDI_CDC_DATA_DESC_3_HS UDI_CDC_DATA_DESC_HS(3)
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_4
#define UDI_CDC_IAD_STRING_ID_4 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_4
#define UDI_CDC_COMM_STRING_ID_4 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_4
#define UDI_CDC_DATA_STRING_ID_4 0
#endif
#define UDI_CDC_IAD_DESC_4 UDI_CDC_IAD_DESC(4)
#define UDI_CDC_COMM_DESC_4 UDI_CDC_COMM_DESC(4)
#define UDI_CDC_DATA_DESC_4_FS UDI_CDC_DATA_DESC_FS(4)
#define UDI_CDC_DATA_DESC_4_HS UDI_CDC_DATA_DESC_HS(4)
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_5
#define UDI_CDC_IAD_STRING_ID_5 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_5
#define UDI_CDC_COMM_STRING_ID_5 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_5
#define UDI_CDC_DATA_STRING_ID_5 0
#endif
#define UDI_CDC_IAD_DESC_5 UDI_CDC_IAD_DESC(5)
#define UDI_CDC_COMM_DESC_5 UDI_CDC_COMM_DESC(5)
#define UDI_CDC_DATA_DESC_5_FS UDI_CDC_DATA_DESC_FS(5)
#define UDI_CDC_DATA_DESC_5_HS UDI_CDC_DATA_DESC_HS(5)
//! By default no string associated to these interfaces
#ifndef UDI_CDC_IAD_STRING_ID_6
#define UDI_CDC_IAD_STRING_ID_6 0
#endif
#ifndef UDI_CDC_COMM_STRING_ID_6
#define UDI_CDC_COMM_STRING_ID_6 0
#endif
#ifndef UDI_CDC_DATA_STRING_ID_6
#define UDI_CDC_DATA_STRING_ID_6 0
#endif
#define UDI_CDC_IAD_DESC_6 UDI_CDC_IAD_DESC(6)
#define UDI_CDC_COMM_DESC_6 UDI_CDC_COMM_DESC(6)
#define UDI_CDC_DATA_DESC_6_FS UDI_CDC_DATA_DESC_FS(6)
#define UDI_CDC_DATA_DESC_6_HS UDI_CDC_DATA_DESC_HS(6)
//@}
//! Content of CDC IAD interface descriptor for all speeds
#define UDI_CDC_IAD_DESC(port) { \
.bLength = sizeof(usb_iad_desc_t),\
.bDescriptorType = USB_DT_IAD,\
.bInterfaceCount = 2,\
.bFunctionClass = CDC_CLASS_COMM,\
.bFunctionSubClass = CDC_SUBCLASS_ACM,\
.bFunctionProtocol = CDC_PROTOCOL_V25TER,\
.bFirstInterface = UDI_CDC_COMM_IFACE_NUMBER_##port,\
.iFunction = UDI_CDC_IAD_STRING_ID_##port,\
}
//! Content of CDC COMM interface descriptor for all speeds
#define UDI_CDC_COMM_DESC(port) { \
.iface.bLength = sizeof(usb_iface_desc_t),\
.iface.bDescriptorType = USB_DT_INTERFACE,\
.iface.bAlternateSetting = 0,\
.iface.bNumEndpoints = 1,\
.iface.bInterfaceClass = CDC_CLASS_COMM,\
.iface.bInterfaceSubClass = CDC_SUBCLASS_ACM,\
.iface.bInterfaceProtocol = CDC_PROTOCOL_V25TER,\
.header.bFunctionLength = sizeof(usb_cdc_hdr_desc_t),\
.header.bDescriptorType = CDC_CS_INTERFACE,\
.header.bDescriptorSubtype = CDC_SCS_HEADER,\
.header.bcdCDC = LE16(0x0110),\
.call_mgmt.bFunctionLength = sizeof(usb_cdc_call_mgmt_desc_t),\
.call_mgmt.bDescriptorType = CDC_CS_INTERFACE,\
.call_mgmt.bDescriptorSubtype = CDC_SCS_CALL_MGMT,\
.call_mgmt.bmCapabilities = \
CDC_CALL_MGMT_SUPPORTED | CDC_CALL_MGMT_OVER_DCI,\
.acm.bFunctionLength = sizeof(usb_cdc_acm_desc_t),\
.acm.bDescriptorType = CDC_CS_INTERFACE,\
.acm.bDescriptorSubtype = CDC_SCS_ACM,\
.acm.bmCapabilities = CDC_ACM_SUPPORT_LINE_REQUESTS,\
.union_desc.bFunctionLength = sizeof(usb_cdc_union_desc_t),\
.union_desc.bDescriptorType = CDC_CS_INTERFACE,\
.union_desc.bDescriptorSubtype= CDC_SCS_UNION,\
.ep_notify.bLength = sizeof(usb_ep_desc_t),\
.ep_notify.bDescriptorType = USB_DT_ENDPOINT,\
.ep_notify.bmAttributes = USB_EP_TYPE_INTERRUPT,\
.ep_notify.wMaxPacketSize = LE16(UDI_CDC_COMM_EP_SIZE),\
.ep_notify.bInterval = 0x10,\
.ep_notify.bEndpointAddress = UDI_CDC_COMM_EP_##port,\
.iface.bInterfaceNumber = UDI_CDC_COMM_IFACE_NUMBER_##port,\
.call_mgmt.bDataInterface = UDI_CDC_DATA_IFACE_NUMBER_##port,\
.union_desc.bMasterInterface = UDI_CDC_COMM_IFACE_NUMBER_##port,\
.union_desc.bSlaveInterface0 = UDI_CDC_DATA_IFACE_NUMBER_##port,\
.iface.iInterface = UDI_CDC_COMM_STRING_ID_##port,\
}
//! Content of CDC DATA interface descriptors
#define UDI_CDC_DATA_DESC_COMMON \
.iface.bLength = sizeof(usb_iface_desc_t),\
.iface.bDescriptorType = USB_DT_INTERFACE,\
.iface.bAlternateSetting = 0,\
.iface.bNumEndpoints = 2,\
.iface.bInterfaceClass = CDC_CLASS_DATA,\
.iface.bInterfaceSubClass = 0,\
.iface.bInterfaceProtocol = 0,\
.ep_in.bLength = sizeof(usb_ep_desc_t),\
.ep_in.bDescriptorType = USB_DT_ENDPOINT,\
.ep_in.bmAttributes = USB_EP_TYPE_BULK,\
.ep_in.bInterval = 0,\
.ep_out.bLength = sizeof(usb_ep_desc_t),\
.ep_out.bDescriptorType = USB_DT_ENDPOINT,\
.ep_out.bmAttributes = USB_EP_TYPE_BULK,\
.ep_out.bInterval = 0,
#define UDI_CDC_DATA_DESC_FS(port) { \
UDI_CDC_DATA_DESC_COMMON \
.ep_in.wMaxPacketSize = LE16(UDI_CDC_DATA_EPS_FS_SIZE),\
.ep_out.wMaxPacketSize = LE16(UDI_CDC_DATA_EPS_FS_SIZE),\
.ep_in.bEndpointAddress = UDI_CDC_DATA_EP_IN_##port,\
.ep_out.bEndpointAddress = UDI_CDC_DATA_EP_OUT_##port,\
.iface.bInterfaceNumber = UDI_CDC_DATA_IFACE_NUMBER_##port,\
.iface.iInterface = UDI_CDC_DATA_STRING_ID_##port,\
}
#define UDI_CDC_DATA_DESC_HS(port) { \
UDI_CDC_DATA_DESC_COMMON \
.ep_in.wMaxPacketSize = LE16(UDI_CDC_DATA_EPS_HS_SIZE),\
.ep_out.wMaxPacketSize = LE16(UDI_CDC_DATA_EPS_HS_SIZE),\
.ep_in.bEndpointAddress = UDI_CDC_DATA_EP_IN_##port,\
.ep_out.bEndpointAddress = UDI_CDC_DATA_EP_OUT_##port,\
.iface.bInterfaceNumber = UDI_CDC_DATA_IFACE_NUMBER_##port,\
.iface.iInterface = UDI_CDC_DATA_STRING_ID_##port,\
}
//@}
/**
* \ingroup udi_group
* \defgroup udi_cdc_group USB Device Interface (UDI) for Communication Class Device (CDC)
*
* Common APIs used by high level application to use this USB class.
*
* These routines are used to transfer and control data
* to/from USB CDC endpoint.
*
* See \ref udi_cdc_quickstart.
* @{
*/
/**
* \name Interface for application with single CDC interface support
*/
//@{
/**
* \brief Notify a state change of DCD signal
*
* \param b_set DCD is enabled if true, else disabled
*/
void udi_cdc_ctrl_signal_dcd(bool b_set);
/**
* \brief Notify a state change of DSR signal
*
* \param b_set DSR is enabled if true, else disabled
*/
void udi_cdc_ctrl_signal_dsr(bool b_set);
/**
* \brief Notify a framing error
*/
void udi_cdc_signal_framing_error(void);
/**
* \brief Notify a parity error
*/
void udi_cdc_signal_parity_error(void);
/**
* \brief Notify a overrun
*/
void udi_cdc_signal_overrun(void);
/**
* \brief Gets the number of byte received
*
* \return the number of data available
*/
iram_size_t udi_cdc_get_nb_received_data(void);
/**
* \brief This function checks if a character has been received on the CDC line
*
* \return \c 1 if a byte is ready to be read.
*/
bool udi_cdc_is_rx_ready(void);
/**
* \brief Waits and gets a value on CDC line
*
* \return value read on CDC line
*/
int udi_cdc_getc(void);
/**
* \brief Reads a RAM buffer on CDC line
*
* \param buf Values read
* \param size Number of value read
*
* \return the number of data remaining
*/
iram_size_t udi_cdc_read_buf(void* buf, iram_size_t size);
/**
* \brief Non polling reads of a up to 'size' data from CDC line
*
* \param port Communication port number to manage
* \param buf Buffer where to store read data
* \param size Maximum number of data to read (size of buffer)
*
* \return the number of data effectively read
*/
iram_size_t udi_cdc_read_no_polling(void* buf, iram_size_t size);
/**
* \brief Gets the number of free byte in TX buffer
*
* \return the number of free byte in TX buffer
*/
iram_size_t udi_cdc_get_free_tx_buffer(void);
/**
* \brief This function checks if a new character sent is possible
* The type int is used to support scanf redirection from compiler LIB.
*
* \return \c 1 if a new character can be sent
*/
bool udi_cdc_is_tx_ready(void);
/**
* \brief Puts a byte on CDC line
* The type int is used to support printf redirection from compiler LIB.
*
* \param value Value to put
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
int udi_cdc_putc(int value);
/**
* \brief Writes a RAM buffer on CDC line
*
* \param buf Values to write
* \param size Number of value to write
*
* \return the number of data remaining
*/
iram_size_t udi_cdc_write_buf(const void* buf, iram_size_t size);
//@}
/**
* \name Interface for application with multi CDC interfaces support
*/
//@{
/**
* \brief Notify a state change of DCD signal
*
* \param port Communication port number to manage
* \param b_set DCD is enabled if true, else disabled
*/
void udi_cdc_multi_ctrl_signal_dcd(uint8_t port, bool b_set);
/**
* \brief Notify a state change of DSR signal
*
* \param port Communication port number to manage
* \param b_set DSR is enabled if true, else disabled
*/
void udi_cdc_multi_ctrl_signal_dsr(uint8_t port, bool b_set);
/**
* \brief Notify a framing error
*
* \param port Communication port number to manage
*/
void udi_cdc_multi_signal_framing_error(uint8_t port);
/**
* \brief Notify a parity error
*
* \param port Communication port number to manage
*/
void udi_cdc_multi_signal_parity_error(uint8_t port);
/**
* \brief Notify a overrun
*
* \param port Communication port number to manage
*/
void udi_cdc_multi_signal_overrun(uint8_t port);
/**
* \brief Gets the number of byte received
*
* \param port Communication port number to manage
*
* \return the number of data available
*/
iram_size_t udi_cdc_multi_get_nb_received_data(uint8_t port);
/**
* \brief This function checks if a character has been received on the CDC line
*
* \param port Communication port number to manage
*
* \return \c 1 if a byte is ready to be read.
*/
bool udi_cdc_multi_is_rx_ready(uint8_t port);
/**
* \brief Waits and gets a value on CDC line
*
* \param port Communication port number to manage
*
* \return value read on CDC line
*/
int udi_cdc_multi_getc(uint8_t port);
/**
* \brief Reads a RAM buffer on CDC line
*
* \param port Communication port number to manage
* \param buf Values read
* \param size Number of values read
*
* \return the number of data remaining
*/
iram_size_t udi_cdc_multi_read_buf(uint8_t port, void* buf, iram_size_t size);
/**
* \brief Gets the number of free byte in TX buffer
*
* \param port Communication port number to manage
*
* \return the number of free byte in TX buffer
*/
iram_size_t udi_cdc_multi_get_free_tx_buffer(uint8_t port);
/**
* \brief This function checks if a new character sent is possible
* The type int is used to support scanf redirection from compiler LIB.
*
* \param port Communication port number to manage
*
* \return \c 1 if a new character can be sent
*/
bool udi_cdc_multi_is_tx_ready(uint8_t port);
/**
* \brief Puts a byte on CDC line
* The type int is used to support printf redirection from compiler LIB.
*
* \param port Communication port number to manage
* \param value Value to put
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
int udi_cdc_multi_putc(uint8_t port, int value);
/**
* \brief Writes a RAM buffer on CDC line
*
* \param port Communication port number to manage
* \param buf Values to write
* \param size Number of value to write
*
* \return the number of data remaining
*/
iram_size_t udi_cdc_multi_write_buf(uint8_t port, const void* buf, iram_size_t size);
//@}
//@}
/**
* \page udi_cdc_quickstart Quick start guide for USB device Communication Class Device module (UDI CDC)
*
* This is the quick start guide for the \ref udi_cdc_group
* "USB device interface CDC module (UDI CDC)" with step-by-step instructions on
* how to configure and use the modules in a selection of use cases.
*
* The use cases contain several code fragments. The code fragments in the
* steps for setup can be copied into a custom initialization function, while
* the steps for usage can be copied into, e.g., the main application function.
*
* \section udi_cdc_basic_use_case Basic use case
* In this basic use case, the "USB CDC (Single Interface Device)" module is used
* with only one communication port.
* The "USB CDC (Composite Device)" module usage is described in \ref udi_cdc_use_cases
* "Advanced use cases".
*
* \section udi_cdc_basic_use_case_setup Setup steps
* \subsection udi_cdc_basic_use_case_setup_prereq Prerequisites
* \copydetails udc_basic_use_case_setup_prereq
* \subsection udi_cdc_basic_use_case_setup_code Example code
* \copydetails udc_basic_use_case_setup_code
* \subsection udi_cdc_basic_use_case_setup_flow Workflow
* \copydetails udc_basic_use_case_setup_flow
*
* \section udi_cdc_basic_use_case_usage Usage steps
*
* \subsection udi_cdc_basic_use_case_usage_code Example code
* Content of conf_usb.h:
* \code
#define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable()
extern bool my_callback_cdc_enable(void);
#define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable()
extern void my_callback_cdc_disable(void);
#define UDI_CDC_LOW_RATE
#define UDI_CDC_DEFAULT_RATE 115200
#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
#define UDI_CDC_DEFAULT_DATABITS 8
#include "udi_cdc_conf.h" // At the end of conf_usb.h file
\endcode
*
* Add to application C-file:
* \code
static bool my_flag_autorize_cdc_transfert = false;
bool my_callback_cdc_enable(void)
{
my_flag_autorize_cdc_transfert = true;
return true;
}
void my_callback_cdc_disable(void)
{
my_flag_autorize_cdc_transfert = false;
}
void task(void)
{
if (my_flag_autorize_cdc_transfert) {
udi_cdc_putc('A');
udi_cdc_getc();
}
}
\endcode
*
* \subsection udi_cdc_basic_use_case_setup_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following configuration,
* which is the USB device CDC configuration:
* - \code #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for CDC \endcode
* \note The USB serial number is mandatory when a CDC interface is used.
* - \code #define UDI_CDC_ENABLE_EXT(port) my_callback_cdc_enable()
extern bool my_callback_cdc_enable(void); \endcode
* \note After the device enumeration (detecting and identifying USB devices),
* the USB host starts the device configuration. When the USB CDC interface
* from the device is accepted by the host, the USB host enables this interface and the
* UDI_CDC_ENABLE_EXT() callback function is called and return true.
* Thus, when this event is received, the data transfer on CDC interface are authorized.
* - \code #define UDI_CDC_DISABLE_EXT(port) my_callback_cdc_disable()
extern void my_callback_cdc_disable(void); \endcode
* \note When the USB device is unplugged or is reset by the USB host, the USB
* interface is disabled and the UDI_CDC_DISABLE_EXT() callback function
* is called. Thus, the data transfer must be stopped on CDC interface.
* - \code #define UDI_CDC_LOW_RATE \endcode
* \note Define it when the transfer CDC Device to Host is a low rate
* (<512000 bauds) to reduce CDC buffers size.
* - \code #define UDI_CDC_DEFAULT_RATE 115200
#define UDI_CDC_DEFAULT_STOPBITS CDC_STOP_BITS_1
#define UDI_CDC_DEFAULT_PARITY CDC_PAR_NONE
#define UDI_CDC_DEFAULT_DATABITS 8 \endcode
* \note Default configuration of communication port at startup.
* -# Send or wait data on CDC line:
* - \code // Waits and gets a value on CDC line
int udi_cdc_getc(void);
// Reads a RAM buffer on CDC line
iram_size_t udi_cdc_read_buf(int *buf, iram_size_t size);
// Puts a byte on CDC line
int udi_cdc_putc(int value);
// Writes a RAM buffer on CDC line
iram_size_t udi_cdc_write_buf(const int *buf, iram_size_t size); \endcode
*
* \section udi_cdc_use_cases Advanced use cases
* For more advanced use of the UDI CDC module, see the following use cases:
* - \subpage udi_cdc_use_case_composite
* - \subpage udc_use_case_1
* - \subpage udc_use_case_2
* - \subpage udc_use_case_3
* - \subpage udc_use_case_4
* - \subpage udc_use_case_5
* - \subpage udc_use_case_6
*/
/**
* \page udi_cdc_use_case_composite CDC in a composite device
*
* A USB Composite Device is a USB Device which uses more than one USB class.
* In this use case, the "USB CDC (Composite Device)" module is used to
* create a USB composite device. Thus, this USB module can be associated with
* another "Composite Device" module, like "USB HID Mouse (Composite Device)".
*
* Also, you can refer to application note
* <A href="https://www.atmel.com/dyn/resources/prod_documents/doc8445.pdf">
* AVR4902 ASF - USB Composite Device</A>.
*
* \section udi_cdc_use_case_composite_setup Setup steps
* For the setup code of this use case to work, the
* \ref udi_cdc_basic_use_case "basic use case" must be followed.
*
* \section udi_cdc_use_case_composite_usage Usage steps
*
* \subsection udi_cdc_use_case_composite_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_EP_CTRL_SIZE 64
#define USB_DEVICE_NB_INTERFACE (X+2)
#define USB_DEVICE_MAX_EP (X+3)
#define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_COMM_IFACE_NUMBER_0 X+0
#define UDI_CDC_DATA_IFACE_NUMBER_0 X+1
#define UDI_COMPOSITE_DESC_T \
usb_iad_desc_t udi_cdc_iad; \
udi_cdc_comm_desc_t udi_cdc_comm; \
udi_cdc_data_desc_t udi_cdc_data; \
...
#define UDI_COMPOSITE_DESC_FS \
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
.udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
...
#define UDI_COMPOSITE_DESC_HS \
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
.udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
...
#define UDI_COMPOSITE_API \
&udi_api_cdc_comm, \
&udi_api_cdc_data, \
...
\endcode
*
* \subsection udi_cdc_use_case_composite_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters
* required for a USB composite device configuration:
* - \code // Endpoint control size, This must be:
// - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM)
// - 64 for a high speed device
#define USB_DEVICE_EP_CTRL_SIZE 64
// Total Number of interfaces on this USB device.
// Add 2 for CDC.
#define USB_DEVICE_NB_INTERFACE (X+2)
// Total number of endpoints on this USB device.
// This must include each endpoint for each interface.
// Add 3 for CDC.
#define USB_DEVICE_MAX_EP (X+3) \endcode
* -# Ensure that conf_usb.h contains the description of
* composite device:
* - \code // The endpoint numbers chosen by you for the CDC.
// The endpoint numbers starting from 1.
#define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
// The interface index of an interface starting from 0
#define UDI_CDC_COMM_IFACE_NUMBER_0 X+0
#define UDI_CDC_DATA_IFACE_NUMBER_0 X+1 \endcode
* -# Ensure that conf_usb.h contains the following parameters
* required for a USB composite device configuration:
* - \code // USB Interfaces descriptor structure
#define UDI_COMPOSITE_DESC_T \
...
usb_iad_desc_t udi_cdc_iad; \
udi_cdc_comm_desc_t udi_cdc_comm; \
udi_cdc_data_desc_t udi_cdc_data; \
...
// USB Interfaces descriptor value for Full Speed
#define UDI_COMPOSITE_DESC_FS \
...
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
.udi_cdc_data = UDI_CDC_DATA_DESC_0_FS, \
...
// USB Interfaces descriptor value for High Speed
#define UDI_COMPOSITE_DESC_HS \
...
.udi_cdc_iad = UDI_CDC_IAD_DESC_0, \
.udi_cdc_comm = UDI_CDC_COMM_DESC_0, \
.udi_cdc_data = UDI_CDC_DATA_DESC_0_HS, \
...
// USB Interface APIs
#define UDI_COMPOSITE_API \
...
&udi_api_cdc_comm, \
&udi_api_cdc_data, \
... \endcode
* - \note The descriptors order given in the four lists above must be the
* same as the order defined by all interface indexes. The interface index
* orders are defined through UDI_X_IFACE_NUMBER defines.\n
* Also, the CDC requires a USB Interface Association Descriptor (IAD) for
* composite device.
*/
#ifdef __cplusplus
}
#endif
#endif // _UDI_CDC_H_

View File

@ -0,0 +1,156 @@
/**
* \file
*
* \brief Default CDC configuration for a USB Device with a single interface
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDI_CDC_CONF_H_
#define _UDI_CDC_CONF_H_
#include "usb_protocol_cdc.h"
#include "conf_usb.h"
#ifndef UDI_CDC_PORT_NB
# define UDI_CDC_PORT_NB 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup udi_cdc_group_single_desc
* @{
*/
//! Control endpoint size (Endpoint 0)
#define USB_DEVICE_EP_CTRL_SIZE 64
#if XMEGA
/**
* \name Endpoint configuration on XMEGA
* The XMEGA supports a IN and OUT endpoint with the same number endpoint,
* thus XMEGA can support up to 7 CDC interfaces.
*/
//@{
#define UDI_CDC_DATA_EP_IN_0 ( 1 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_0 ( 2 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_0 ( 2 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_DATA_EP_IN_1 ( 3 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_1 ( 4 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_1 ( 4 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_DATA_EP_IN_2 ( 5 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_2 ( 6 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_2 ( 6 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_DATA_EP_IN_3 ( 7 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_3 ( 8 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_3 ( 8 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_DATA_EP_IN_4 ( 9 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_4 (10 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_4 (10 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_DATA_EP_IN_5 (11 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_5 (12 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_5 (12 | USB_EP_DIR_IN) // Notify endpoint
#define UDI_CDC_DATA_EP_IN_6 (13 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_6 (14 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_6 (14 | USB_EP_DIR_IN) // Notify endpoint
//! 2 endpoints numbers used per CDC interface
#define USB_DEVICE_MAX_EP (2*UDI_CDC_PORT_NB)
//@}
#else
/**
* \name Default endpoint configuration
* The USBB, UDP, UDPHS and UOTGHS interfaces can support up to 2 CDC interfaces.
*/
//@{
# if UDI_CDC_PORT_NB > 2
# error USBB, UDP, UDPHS and UOTGHS interfaces have not enough endpoints.
# endif
#define UDI_CDC_DATA_EP_IN_0 (1 | USB_EP_DIR_IN) // TX
#define UDI_CDC_DATA_EP_OUT_0 (2 | USB_EP_DIR_OUT) // RX
#define UDI_CDC_COMM_EP_0 (3 | USB_EP_DIR_IN) // Notify endpoint
# if SAM3U
/* For 3U max endpoint size of 4 is 64, use 5 and 6 as bulk tx and rx */
# define UDI_CDC_DATA_EP_IN_1 (6 | USB_EP_DIR_IN) // TX
# define UDI_CDC_DATA_EP_OUT_1 (5 | USB_EP_DIR_OUT) // RX
# define UDI_CDC_COMM_EP_1 (4 | USB_EP_DIR_IN) // Notify
# else
# define UDI_CDC_DATA_EP_IN_1 (4 | USB_EP_DIR_IN) // TX
# define UDI_CDC_DATA_EP_OUT_1 (5 | USB_EP_DIR_OUT) // RX
# define UDI_CDC_COMM_EP_1 (6 | USB_EP_DIR_IN) // Notify
# endif
//! 3 endpoints used per CDC interface
#undef USB_DEVICE_MAX_EP // undefine this definition in header file
#define USB_DEVICE_MAX_EP (3*UDI_CDC_PORT_NB)
//@}
#endif
/**
* \name Default Interface numbers
*/
//@{
#define UDI_CDC_COMM_IFACE_NUMBER_0 0
#define UDI_CDC_DATA_IFACE_NUMBER_0 1
#define UDI_CDC_COMM_IFACE_NUMBER_1 2
#define UDI_CDC_DATA_IFACE_NUMBER_1 3
#define UDI_CDC_COMM_IFACE_NUMBER_2 4
#define UDI_CDC_DATA_IFACE_NUMBER_2 5
#define UDI_CDC_COMM_IFACE_NUMBER_3 6
#define UDI_CDC_DATA_IFACE_NUMBER_3 7
#define UDI_CDC_COMM_IFACE_NUMBER_4 8
#define UDI_CDC_DATA_IFACE_NUMBER_4 9
#define UDI_CDC_COMM_IFACE_NUMBER_5 10
#define UDI_CDC_DATA_IFACE_NUMBER_5 11
#define UDI_CDC_COMM_IFACE_NUMBER_6 12
#define UDI_CDC_DATA_IFACE_NUMBER_6 13
//@}
//@}
#ifdef __cplusplus
}
#endif
#endif // _UDI_CDC_CONF_H_

View File

@ -0,0 +1,261 @@
/**
* \file
*
* \brief Default descriptors for a USB Device with a single interface CDC
*
* Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifdef ARDUINO_ARCH_SAM
#include "conf_usb.h"
#include "udd.h"
#include "udc_desc.h"
#include "udi_cdc.h"
#if DISABLED(SDSUPPORT)
/**
* \defgroup udi_cdc_group_single_desc USB device descriptors for a single interface
*
* The following structures provide the USB device descriptors required for
* USB Device with a single interface CDC.
*
* It is ready to use and do not require more definition.
*
* @{
*/
//! Two interfaces for a CDC device
#define USB_DEVICE_NB_INTERFACE (2*UDI_CDC_PORT_NB)
#ifdef USB_DEVICE_LPM_SUPPORT
# define USB_VERSION USB_V2_1
#else
# define USB_VERSION USB_V2_0
#endif
//! USB Device Descriptor
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = {
.bLength = sizeof(usb_dev_desc_t),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = LE16(USB_VERSION),
#if UDI_CDC_PORT_NB > 1
.bDeviceClass = 0,
#else
.bDeviceClass = CDC_CLASS_DEVICE,
#endif
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE,
.idVendor = LE16(USB_DEVICE_VENDOR_ID),
.idProduct = LE16(USB_DEVICE_PRODUCT_ID),
.bcdDevice = LE16((USB_DEVICE_MAJOR_VERSION << 8)
| USB_DEVICE_MINOR_VERSION),
#ifdef USB_DEVICE_MANUFACTURE_NAME
.iManufacturer = 1,
#else
.iManufacturer = 0, // No manufacture string
#endif
#ifdef USB_DEVICE_PRODUCT_NAME
.iProduct = 2,
#else
.iProduct = 0, // No product string
#endif
#if (defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER)
.iSerialNumber = 3,
#else
.iSerialNumber = 0, // No serial string
#endif
.bNumConfigurations = 1
};
#ifdef USB_DEVICE_HS_SUPPORT
//! USB Device Qualifier Descriptor for HS
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE usb_dev_qual_desc_t udc_device_qual = {
.bLength = sizeof(usb_dev_qual_desc_t),
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
.bcdUSB = LE16(USB_VERSION),
#if UDI_CDC_PORT_NB > 1
.bDeviceClass = 0,
#else
.bDeviceClass = CDC_CLASS_DEVICE,
#endif
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE,
.bNumConfigurations = 1
};
#endif
#ifdef USB_DEVICE_LPM_SUPPORT
//! USB Device Qualifier Descriptor
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE usb_dev_lpm_desc_t udc_device_lpm = {
.bos.bLength = sizeof(usb_dev_bos_desc_t),
.bos.bDescriptorType = USB_DT_BOS,
.bos.wTotalLength = LE16(sizeof(usb_dev_bos_desc_t) + sizeof(usb_dev_capa_ext_desc_t)),
.bos.bNumDeviceCaps = 1,
.capa_ext.bLength = sizeof(usb_dev_capa_ext_desc_t),
.capa_ext.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.capa_ext.bDevCapabilityType = USB_DC_USB20_EXTENSION,
.capa_ext.bmAttributes = USB_DC_EXT_LPM,
};
#endif
//! Structure for USB Device Configuration Descriptor
COMPILER_PACK_SET(1)
typedef struct {
usb_conf_desc_t conf;
#if UDI_CDC_PORT_NB == 1
udi_cdc_comm_desc_t udi_cdc_comm_0;
udi_cdc_data_desc_t udi_cdc_data_0;
#else
# define UDI_CDC_DESC_STRUCTURE(index, unused) \
usb_iad_desc_t udi_cdc_iad_##index; \
udi_cdc_comm_desc_t udi_cdc_comm_##index; \
udi_cdc_data_desc_t udi_cdc_data_##index;
MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DESC_STRUCTURE, ~)
# undef UDI_CDC_DESC_STRUCTURE
#endif
} udc_desc_t;
COMPILER_PACK_RESET()
//! USB Device Configuration Descriptor filled for full and high speed
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udc_desc_t udc_desc_fs = {
.conf.bLength = sizeof(usb_conf_desc_t),
.conf.bDescriptorType = USB_DT_CONFIGURATION,
.conf.wTotalLength = LE16(sizeof(udc_desc_t)),
.conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE,
.conf.bConfigurationValue = 1,
.conf.iConfiguration = 0,
.conf.bmAttributes = USB_CONFIG_ATTR_MUST_SET | USB_DEVICE_ATTR,
.conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER),
#if UDI_CDC_PORT_NB == 1
.udi_cdc_comm_0 = UDI_CDC_COMM_DESC_0,
.udi_cdc_data_0 = UDI_CDC_DATA_DESC_0_FS,
#else
# define UDI_CDC_DESC_FS(index, unused) \
.udi_cdc_iad_##index = UDI_CDC_IAD_DESC_##index,\
.udi_cdc_comm_##index = UDI_CDC_COMM_DESC_##index,\
.udi_cdc_data_##index = UDI_CDC_DATA_DESC_##index##_FS,
MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DESC_FS, ~)
# undef UDI_CDC_DESC_FS
#endif
};
#ifdef USB_DEVICE_HS_SUPPORT
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udc_desc_t udc_desc_hs = {
.conf.bLength = sizeof(usb_conf_desc_t),
.conf.bDescriptorType = USB_DT_CONFIGURATION,
.conf.wTotalLength = LE16(sizeof(udc_desc_t)),
.conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE,
.conf.bConfigurationValue = 1,
.conf.iConfiguration = 0,
.conf.bmAttributes = USB_CONFIG_ATTR_MUST_SET | USB_DEVICE_ATTR,
.conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER),
#if UDI_CDC_PORT_NB == 1
.udi_cdc_comm_0 = UDI_CDC_COMM_DESC_0,
.udi_cdc_data_0 = UDI_CDC_DATA_DESC_0_HS,
#else
# define UDI_CDC_DESC_HS(index, unused) \
.udi_cdc_iad_##index = UDI_CDC_IAD_DESC_##index, \
.udi_cdc_comm_##index = UDI_CDC_COMM_DESC_##index, \
.udi_cdc_data_##index = UDI_CDC_DATA_DESC_##index##_HS,
MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_DESC_HS, ~)
# undef UDI_CDC_DESC_HS
#endif
};
#endif
/**
* \name UDC structures which content all USB Device definitions
*/
//@{
//! Associate an UDI for each USB interface
UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = {
# define UDI_CDC_API(index, unused) \
&udi_api_cdc_comm, \
&udi_api_cdc_data,
MREPEAT(UDI_CDC_PORT_NB, UDI_CDC_API, ~)
# undef UDI_CDC_API
};
//! Add UDI with USB Descriptors FS & HS
UDC_DESC_STORAGE udc_config_speed_t udc_config_fs[1] = { {
.desc = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc_fs,
.udi_apis = udi_apis,
}};
#ifdef USB_DEVICE_HS_SUPPORT
UDC_DESC_STORAGE udc_config_speed_t udc_config_hs[1] = { {
.desc = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc_hs,
.udi_apis = udi_apis,
}};
#endif
//! Add all information about USB Device in global structure for UDC
UDC_DESC_STORAGE udc_config_t udc_config = {
.confdev_lsfs = &udc_device_desc,
.conf_lsfs = udc_config_fs,
#ifdef USB_DEVICE_HS_SUPPORT
.confdev_hs = &udc_device_desc,
.qualifier = &udc_device_qual,
.conf_hs = udc_config_hs,
#endif
#ifdef USB_DEVICE_LPM_SUPPORT
.conf_bos = &udc_device_lpm.bos,
#else
.conf_bos = NULL,
#endif
};
//@}
//@}
#endif // SDSUPPORT
#endif // ARDUINO_ARCH_SAM

View File

@ -0,0 +1,192 @@
/**
* \file
*
* \brief Descriptors for an USB Composite Device
*
* Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifdef ARDUINO_ARCH_SAM
#include "conf_usb.h"
#include "udd.h"
#include "udc_desc.h"
#if ENABLED(SDSUPPORT)
/**
* \defgroup udi_group_desc Descriptors for a USB Device
* composite
*
* @{
*/
/**INDENT-OFF**/
//! USB Device Descriptor
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = {
.bLength = sizeof(usb_dev_desc_t),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = LE16(USB_V2_0),
.bDeviceClass = CDC_CLASS_MULTI,
.bDeviceSubClass = CDC_SUBCLASS_ACM,
.bDeviceProtocol = CDC_PROTOCOL_V25TER,
.bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE,
.idVendor = LE16(USB_DEVICE_VENDOR_ID),
.idProduct = LE16(USB_DEVICE_PRODUCT_ID),
.bcdDevice = LE16((USB_DEVICE_MAJOR_VERSION << 8)
| USB_DEVICE_MINOR_VERSION),
#ifdef USB_DEVICE_MANUFACTURE_NAME
.iManufacturer = 1,
#else
.iManufacturer = 0, // No manufacture string
#endif
#ifdef USB_DEVICE_PRODUCT_NAME
.iProduct = 2,
#else
.iProduct = 0, // No product string
#endif
#if (defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER)
.iSerialNumber = 3,
#else
.iSerialNumber = 0, // No serial string
#endif
.bNumConfigurations = 1
};
#ifdef USB_DEVICE_HS_SUPPORT
//! USB Device Qualifier Descriptor for HS
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE usb_dev_qual_desc_t udc_device_qual = {
.bLength = sizeof(usb_dev_qual_desc_t),
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
.bcdUSB = LE16(USB_V2_0),
.bDeviceClass = CDC_CLASS_MULTI,
.bDeviceSubClass = CDC_SUBCLASS_ACM,
.bDeviceProtocol = CDC_PROTOCOL_V25TER,
.bMaxPacketSize0 = USB_DEVICE_EP_CTRL_SIZE,
.bNumConfigurations = 1
};
#endif
//! Structure for USB Device Configuration Descriptor
COMPILER_PACK_SET(1)
typedef struct {
usb_conf_desc_t conf;
UDI_COMPOSITE_DESC_T;
} udc_desc_t;
COMPILER_PACK_RESET()
//! USB Device Configuration Descriptor filled for FS
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udc_desc_t udc_desc_fs = {
.conf.bLength = sizeof(usb_conf_desc_t),
.conf.bDescriptorType = USB_DT_CONFIGURATION,
.conf.wTotalLength = LE16(sizeof(udc_desc_t)),
.conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE,
.conf.bConfigurationValue = 1,
.conf.iConfiguration = 0,
.conf.bmAttributes = USB_CONFIG_ATTR_MUST_SET | USB_DEVICE_ATTR,
.conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER),
UDI_COMPOSITE_DESC_FS
};
#ifdef USB_DEVICE_HS_SUPPORT
//! USB Device Configuration Descriptor filled for HS
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udc_desc_t udc_desc_hs = {
.conf.bLength = sizeof(usb_conf_desc_t),
.conf.bDescriptorType = USB_DT_CONFIGURATION,
.conf.wTotalLength = LE16(sizeof(udc_desc_t)),
.conf.bNumInterfaces = USB_DEVICE_NB_INTERFACE,
.conf.bConfigurationValue = 1,
.conf.iConfiguration = 0,
.conf.bmAttributes = USB_CONFIG_ATTR_MUST_SET | USB_DEVICE_ATTR,
.conf.bMaxPower = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER),
UDI_COMPOSITE_DESC_HS
};
#endif
/**
* \name UDC structures which contains all USB Device definitions
*/
//@{
//! Associate an UDI for each USB interface
UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = {
UDI_COMPOSITE_API
};
//! Add UDI with USB Descriptors FS
UDC_DESC_STORAGE udc_config_speed_t udc_config_lsfs[1] = {{
.desc = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc_fs,
.udi_apis = udi_apis,
}};
#ifdef USB_DEVICE_HS_SUPPORT
//! Add UDI with USB Descriptors HS
UDC_DESC_STORAGE udc_config_speed_t udc_config_hs[1] = {{
.desc = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc_hs,
.udi_apis = udi_apis,
}};
#endif
//! Add all information about USB Device in global structure for UDC
UDC_DESC_STORAGE udc_config_t udc_config = {
.confdev_lsfs = &udc_device_desc,
.conf_lsfs = udc_config_lsfs,
#ifdef USB_DEVICE_HS_SUPPORT
.confdev_hs = &udc_device_desc,
.qualifier = &udc_device_qual,
.conf_hs = udc_config_hs,
#endif
};
//@}
/**INDENT-ON**/
//@}
#endif // ARDUINO_ARCH_SAM
#endif // SDSUPPORT

1132
src/HAL/DUE/usb/udi_msc.c Normal file

File diff suppressed because it is too large Load Diff

376
src/HAL/DUE/usb/udi_msc.h Normal file
View File

@ -0,0 +1,376 @@
/**
* \file
*
* \brief USB Device Mass Storage Class (MSC) interface definitions.
*
* Copyright (c) 2009-2016 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _UDI_MSC_H_
#define _UDI_MSC_H_
#include "conf_usb.h"
#include "usb_protocol.h"
#include "usb_protocol_msc.h"
#include "udd.h"
#include "udc_desc.h"
#include "udi.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \addtogroup udi_msc_group_udc
* @{
*/
//! Global structure which contains standard UDI interface for UDC
extern UDC_DESC_STORAGE udi_api_t udi_api_msc;
//@}
/**
* \ingroup udi_msc_group
* \defgroup udi_msc_group USB interface descriptors
*
* The following structures provide predefined USB interface descriptors.
* It must be used to define the final USB descriptors.
*/
//@{
//! Interface descriptor structure for MSC
typedef struct {
usb_iface_desc_t iface;
usb_ep_desc_t ep_in;
usb_ep_desc_t ep_out;
} udi_msc_desc_t;
//! By default no string associated to this interface
#ifndef UDI_MSC_STRING_ID
#define UDI_MSC_STRING_ID 0
#endif
//! MSC endpoints size for full speed
#define UDI_MSC_EPS_SIZE_FS 64
//! MSC endpoints size for high speed
#define UDI_MSC_EPS_SIZE_HS 512
//! Content of MSC interface descriptor for all speeds
#define UDI_MSC_DESC \
.iface.bLength = sizeof(usb_iface_desc_t),\
.iface.bDescriptorType = USB_DT_INTERFACE,\
.iface.bInterfaceNumber = UDI_MSC_IFACE_NUMBER,\
.iface.bAlternateSetting = 0,\
.iface.bNumEndpoints = 2,\
.iface.bInterfaceClass = MSC_CLASS,\
.iface.bInterfaceSubClass = MSC_SUBCLASS_TRANSPARENT,\
.iface.bInterfaceProtocol = MSC_PROTOCOL_BULK,\
.iface.iInterface = UDI_MSC_STRING_ID,\
.ep_in.bLength = sizeof(usb_ep_desc_t),\
.ep_in.bDescriptorType = USB_DT_ENDPOINT,\
.ep_in.bEndpointAddress = UDI_MSC_EP_IN,\
.ep_in.bmAttributes = USB_EP_TYPE_BULK,\
.ep_in.bInterval = 0,\
.ep_out.bLength = sizeof(usb_ep_desc_t),\
.ep_out.bDescriptorType = USB_DT_ENDPOINT,\
.ep_out.bEndpointAddress = UDI_MSC_EP_OUT,\
.ep_out.bmAttributes = USB_EP_TYPE_BULK,\
.ep_out.bInterval = 0,
//! Content of MSC interface descriptor for full speed only
#define UDI_MSC_DESC_FS {\
UDI_MSC_DESC \
.ep_in.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\
.ep_out.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_FS),\
}
//! Content of MSC interface descriptor for high speed only
#define UDI_MSC_DESC_HS {\
UDI_MSC_DESC \
.ep_in.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_HS),\
.ep_out.wMaxPacketSize = LE16(UDI_MSC_EPS_SIZE_HS),\
}
//@}
/**
* \ingroup udi_group
* \defgroup udi_msc_group USB Device Interface (UDI) for Mass Storage Class (MSC)
*
* Common APIs used by high level application to use this USB class.
*
* These routines are used by memory to transfer its data
* to/from USB MSC endpoints.
*
* See \ref udi_msc_quickstart.
* @{
*/
/**
* \brief Process the background read/write commands
*
* Routine called by the main loop
*/
bool udi_msc_process_trans(void);
/**
* \brief Transfers data to/from USB MSC endpoints
*
*
* \param b_read Memory to USB, if true
* \param block Buffer on Internal RAM to send or fill
* \param block_size Buffer size to send or fill
* \param callback Function to call at the end of transfer.
* If NULL then the routine exit when transfer is finish.
*
* \return \c 1 if function was successfully done, otherwise \c 0.
*/
bool udi_msc_trans_block(bool b_read, uint8_t * block, iram_size_t block_size,
void (*callback) (udd_ep_status_t status, iram_size_t n, udd_ep_id_t ep));
//@}
#ifdef __cplusplus
}
#endif
/**
* \page udi_msc_quickstart Quick start guide for USB device Mass Storage module (UDI MSC)
*
* This is the quick start guide for the \ref udi_msc_group
* "USB device interface MSC module (UDI MSC)" with step-by-step instructions on
* how to configure and use the modules in a selection of use cases.
*
* The use cases contain several code fragments. The code fragments in the
* steps for setup can be copied into a custom initialization function, while
* the steps for usage can be copied into, e.g., the main application function.
*
* \section udi_msc_basic_use_case Basic use case
* In this basic use case, the "USB MSC (Single Interface Device)" module is used.
* The "USB MSC (Composite Device)" module usage is described in \ref udi_msc_use_cases
* "Advanced use cases".
*
* \section udi_msc_basic_use_case_setup Setup steps
* \subsection udi_msc_basic_use_case_setup_prereq Prerequisites
* \copydetails udc_basic_use_case_setup_prereq
* \subsection udi_msc_basic_use_case_setup_code Example code
* \copydetails udc_basic_use_case_setup_code
* \subsection udi_msc_basic_use_case_setup_flow Workflow
* \copydetails udc_basic_use_case_setup_flow
*
* \section udi_msc_basic_use_case_usage Usage steps
*
* \subsection udi_msc_basic_use_case_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC
#define UDI_MSC_GLOBAL_VENDOR_ID \
'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
'1', '.', '0', '0'
#define UDI_MSC_ENABLE_EXT() my_callback_msc_enable()
extern bool my_callback_msc_enable(void);
#define UDI_MSC_DISABLE_EXT() my_callback_msc_disable()
extern void my_callback_msc_disable(void);
#include "udi_msc_conf.h" // At the end of conf_usb.h file
\endcode
*
* Add to application C-file:
* \code
static bool my_flag_autorize_msc_transfert = false;
bool my_callback_msc_enable(void)
{
my_flag_autorize_msc_transfert = true;
return true;
}
void my_callback_msc_disable(void)
{
my_flag_autorize_msc_transfert = false;
}
void task(void)
{
udi_msc_process_trans();
}
\endcode
*
* \subsection udi_msc_basic_use_case_setup_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following configuration,
* which is the USB device MSC configuration:
* - \code #define USB_DEVICE_SERIAL_NAME "12...EF" // Disk SN for MSC \endcode
* \note The USB serial number is mandatory when a MSC interface is used.
* - \code //! Vendor name and Product version of MSC interface
#define UDI_MSC_GLOBAL_VENDOR_ID \
'A', 'T', 'M', 'E', 'L', ' ', ' ', ' '
#define UDI_MSC_GLOBAL_PRODUCT_VERSION \
'1', '.', '0', '0' \endcode
* \note The USB MSC interface requires a vendor ID (8 ASCII characters)
* and a product version (4 ASCII characters).
* - \code #define UDI_MSC_ENABLE_EXT() my_callback_msc_enable()
extern bool my_callback_msc_enable(void); \endcode
* \note After the device enumeration (detecting and identifying USB devices),
* the USB host starts the device configuration. When the USB MSC interface
* from the device is accepted by the host, the USB host enables this interface and the
* UDI_MSC_ENABLE_EXT() callback function is called and return true.
* Thus, when this event is received, the tasks which call
* udi_msc_process_trans() must be enabled.
* - \code #define UDI_MSC_DISABLE_EXT() my_callback_msc_disable()
extern void my_callback_msc_disable(void); \endcode
* \note When the USB device is unplugged or is reset by the USB host, the USB
* interface is disabled and the UDI_MSC_DISABLE_EXT() callback function
* is called. Thus, it is recommended to disable the task which is called udi_msc_process_trans().
* -# The MSC is automatically linked with memory control access component
* which provides the memories interfaces. However, the memory data transfers
* must be done outside USB interrupt routine. This is done in the MSC process
* ("udi_msc_process_trans()") called by main loop:
* - \code * void task(void) {
udi_msc_process_trans();
} \endcode
* -# The MSC speed depends on task periodicity. To get the best speed
* the notification callback "UDI_MSC_NOTIFY_TRANS_EXT" can be used to wakeup
* this task (Example, through a mutex):
* - \code #define UDI_MSC_NOTIFY_TRANS_EXT() msc_notify_trans()
void msc_notify_trans(void) {
wakeup_my_task();
} \endcode
*
* \section udi_msc_use_cases Advanced use cases
* For more advanced use of the UDI MSC module, see the following use cases:
* - \subpage udi_msc_use_case_composite
* - \subpage udc_use_case_1
* - \subpage udc_use_case_2
* - \subpage udc_use_case_3
* - \subpage udc_use_case_5
* - \subpage udc_use_case_6
*/
/**
* \page udi_msc_use_case_composite MSC in a composite device
*
* A USB Composite Device is a USB Device which uses more than one USB class.
* In this use case, the "USB MSC (Composite Device)" module is used to
* create a USB composite device. Thus, this USB module can be associated with
* another "Composite Device" module, like "USB HID Mouse (Composite Device)".
*
* Also, you can refer to application note
* <A href="https://www.atmel.com/dyn/resources/prod_documents/doc8445.pdf">
* AVR4902 ASF - USB Composite Device</A>.
*
* \section udi_msc_use_case_composite_setup Setup steps
* For the setup code of this use case to work, the
* \ref udi_msc_basic_use_case "basic use case" must be followed.
*
* \section udi_msc_use_case_composite_usage Usage steps
*
* \subsection udi_msc_use_case_composite_usage_code Example code
* Content of conf_usb.h:
* \code
#define USB_DEVICE_EP_CTRL_SIZE 64
#define USB_DEVICE_NB_INTERFACE (X+1)
#define USB_DEVICE_MAX_EP (X+2)
#define UDI_MSC_EP_IN (X | USB_EP_DIR_IN)
#define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT)
#define UDI_MSC_IFACE_NUMBER X
#define UDI_COMPOSITE_DESC_T \
udi_msc_desc_t udi_msc; \
...
#define UDI_COMPOSITE_DESC_FS \
.udi_msc = UDI_MSC_DESC, \
...
#define UDI_COMPOSITE_DESC_HS \
.udi_msc = UDI_MSC_DESC, \
...
#define UDI_COMPOSITE_API \
&udi_api_msc, \
...
\endcode
*
* \subsection udi_msc_use_case_composite_usage_flow Workflow
* -# Ensure that conf_usb.h is available and contains the following parameters
* required for a USB composite device configuration:
* - \code // Endpoint control size, This must be:
// - 8, 16, 32 or 64 for full speed device (8 is recommended to save RAM)
// - 64 for a high speed device
#define USB_DEVICE_EP_CTRL_SIZE 64
// Total Number of interfaces on this USB device.
// Add 1 for MSC.
#define USB_DEVICE_NB_INTERFACE (X+1)
// Total number of endpoints on this USB device.
// This must include each endpoint for each interface.
// Add 2 for MSC.
#define USB_DEVICE_MAX_EP (X+2) \endcode
* -# Ensure that conf_usb.h contains the description of
* composite device:
* - \code // The endpoint numbers chosen by you for the MSC.
// The endpoint numbers starting from 1.
#define UDI_MSC_EP_IN (X | USB_EP_DIR_IN)
#define UDI_MSC_EP_OUT (Y | USB_EP_DIR_OUT)
// The interface index of an interface starting from 0
#define UDI_MSC_IFACE_NUMBER X \endcode
* -# Ensure that conf_usb.h contains the following parameters
* required for a USB composite device configuration:
* - \code // USB Interfaces descriptor structure
#define UDI_COMPOSITE_DESC_T \
...
udi_msc_desc_t udi_msc; \
...
// USB Interfaces descriptor value for Full Speed
#define UDI_COMPOSITE_DESC_FS \
...
.udi_msc = UDI_MSC_DESC_FS, \
...
// USB Interfaces descriptor value for High Speed
#define UDI_COMPOSITE_DESC_HS \
...
.udi_msc = UDI_MSC_DESC_HS, \
...
// USB Interface APIs
#define UDI_COMPOSITE_API \
...
&udi_api_msc, \
... \endcode
* - \note The descriptors order given in the four lists above must be the
* same as the order defined by all interface indexes. The interface index
* orders are defined through UDI_X_IFACE_NUMBER defines.
*/
#endif // _UDI_MSC_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,664 @@
/**
* \file
*
* \brief USB Device Driver for UOTGHS. Compliant with common UDD driver.
*
* Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef UOTGHS_DEVICE_DUE_H_INCLUDED
#define UOTGHS_DEVICE_DUE_H_INCLUDED
//#include "compiler.h"
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
extern "C" {
#endif
/**INDENT-ON**/
/// @endcond
//! \ingroup udd_group
//! \defgroup udd_udphs_group USB On-The-Go High-Speed Port for device mode (UOTGHS)
//! UOTGHS low-level driver for USB device mode
//!
//! @{
#ifndef UOTGHS_DEVEPTCFG_EPDIR_Pos
// Bit pos is not defined in SAM header file but we need it.
# define UOTGHS_DEVEPTCFG_EPDIR_Pos 8
#endif
//! @name UOTGHS Device IP properties
//! These macros give access to IP properties
//! @{
//! Get maximal number of endpoints
#define udd_get_endpoint_max_nbr() (9)
#define UDD_MAX_PEP_NB (udd_get_endpoint_max_nbr() + 1)
//! Get maximal number of banks of endpoints
#define udd_get_endpoint_bank_max_nbr(ep) ((ep == 0) ? 1 : (( ep <= 2) ? 3 : 2))
//! Get maximal size of endpoint (3X, 1024/64)
#define udd_get_endpoint_size_max(ep) (((ep) == 0) ? 64 : 1024)
//! Get DMA support of endpoints
#define Is_udd_endpoint_dma_supported(ep) ((((ep) >= 1) && ((ep) <= 6)) ? true : false)
//! Get High Band Width support of endpoints
#define Is_udd_endpoint_high_bw_supported(ep) (((ep) >= 2) ? true : false)
//! @}
//! @name UOTGHS Device speeds management
//! @{
//! Enable/disable device low-speed mode
#define udd_low_speed_enable() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_LS))
#define udd_low_speed_disable() (Clr_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_LS))
//! Test if device low-speed mode is forced
#define Is_udd_low_speed_enable() (Tst_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_LS))
#ifdef UOTGHS_DEVCTRL_SPDCONF_HIGH_SPEED
//! Enable high speed mode
# define udd_high_speed_enable() (Wr_bitfield(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_SPDCONF_Msk, 0))
//! Disable high speed mode
# define udd_high_speed_disable() (Wr_bitfield(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_SPDCONF_Msk, 3))
//! Test if controller is in full speed mode
# define Is_udd_full_speed_mode() (Rd_bitfield(UOTGHS->UOTGHS_SR, UOTGHS_SR_SPEED_Msk) == UOTGHS_SR_SPEED_FULL_SPEED)
#else
# define udd_high_speed_enable() do { } while (0)
# define udd_high_speed_disable() do { } while (0)
# define Is_udd_full_speed_mode() true
#endif
//! @}
//! @name UOTGHS Device HS test mode management
//! @{
#ifdef UOTGHS_DEVCTRL_SPDCONF_HIGH_SPEED
//! Enable high speed test mode
# define udd_enable_hs_test_mode() (Wr_bitfield(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_SPDCONF_Msk, 2))
# define udd_enable_hs_test_mode_j() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_TSTJ))
# define udd_enable_hs_test_mode_k() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_TSTK))
# define udd_enable_hs_test_mode_packet() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_TSTPCKT))
#endif
//! @}
//! @name UOTGHS Device vbus management
//! @{
#define udd_enable_vbus_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSTE))
#define udd_disable_vbus_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSTE))
#define Is_udd_vbus_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSTE))
#define Is_udd_vbus_high() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBUS))
#define Is_udd_vbus_low() (!Is_udd_vbus_high())
#define udd_ack_vbus_transition() (UOTGHS->UOTGHS_SCR = UOTGHS_SCR_VBUSTIC)
#define udd_raise_vbus_transition() (UOTGHS->UOTGHS_SFR = UOTGHS_SFR_VBUSTIS)
#define Is_udd_vbus_transition() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBUSTI))
//! @}
//! @name UOTGHS device attach control
//! These macros manage the UOTGHS Device attach.
//! @{
//! Detaches from USB bus
#define udd_detach_device() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_DETACH))
//! Attaches to USB bus
#define udd_attach_device() (Clr_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_DETACH))
//! Test if the device is detached
#define Is_udd_detached() (Tst_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_DETACH))
//! @}
//! @name UOTGHS device bus events control
//! These macros manage the UOTGHS Device bus events.
//! @{
//! Initiates a remote wake-up event
//! @{
#define udd_initiate_remote_wake_up() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_RMWKUP))
#define Is_udd_pending_remote_wake_up() (Tst_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_RMWKUP))
//! @}
//! Manage upstream resume event (=remote wakeup)
//! The USB driver sends a resume signal called "Upstream Resume"
//! @{
#define udd_enable_remote_wake_up_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_UPRSMES)
#define udd_disable_remote_wake_up_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_UPRSMEC)
#define Is_udd_remote_wake_up_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_UPRSME))
#define udd_ack_remote_wake_up_start() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_UPRSMC)
#define udd_raise_remote_wake_up_start() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_UPRSMS)
#define Is_udd_remote_wake_up_start() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_UPRSM))
//! @}
//! Manage downstream resume event (=remote wakeup from host)
//! The USB controller detects a valid "End of Resume" signal initiated by the host
//! @{
#define udd_enable_resume_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_EORSMES)
#define udd_disable_resume_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_EORSMEC)
#define Is_udd_resume_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_EORSME))
#define udd_ack_resume() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_EORSMC)
#define udd_raise_resume() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_EORSMS)
#define Is_udd_resume() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_EORSM))
//! @}
//! Manage wake-up event (=usb line activity)
//! The USB controller is reactivated by a filtered non-idle signal from the lines
//! @{
#define udd_enable_wake_up_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_WAKEUPES)
#define udd_disable_wake_up_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_WAKEUPEC)
#define Is_udd_wake_up_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_WAKEUPE))
#define udd_ack_wake_up() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_WAKEUPC)
#define udd_raise_wake_up() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_WAKEUPS)
#define Is_udd_wake_up() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_WAKEUP))
//! @}
//! Manage reset event
//! Set when a USB "End of Reset" has been detected
//! @{
#define udd_enable_reset_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_EORSTES)
#define udd_disable_reset_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_EORSTEC)
#define Is_udd_reset_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_EORSTE))
#define udd_ack_reset() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_EORSTC)
#define udd_raise_reset() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_EORSTS)
#define Is_udd_reset() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_EORST))
//! @}
//! Manage start of frame event
//! @{
#define udd_enable_sof_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_SOFES)
#define udd_disable_sof_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_SOFEC)
#define Is_udd_sof_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_SOFE))
#define udd_ack_sof() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_SOFC)
#define udd_raise_sof() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_SOFS)
#define Is_udd_sof() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_SOF))
#define udd_frame_number() (Rd_bitfield(UOTGHS->UOTGHS_DEVFNUM, UOTGHS_DEVFNUM_FNUM_Msk))
#define Is_udd_frame_number_crc_error() (Tst_bits(UOTGHS->UOTGHS_DEVFNUM, UOTGHS_DEVFNUM_FNCERR))
//! @}
//! Manage Micro start of frame event (High Speed Only)
//! @{
#define udd_enable_msof_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_MSOFES)
#define udd_disable_msof_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_MSOFEC)
#define Is_udd_msof_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_MSOFE))
#define udd_ack_msof() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVIMR_MSOFE)
#define udd_raise_msof() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_MSOFS)
#define Is_udd_msof() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_MSOF))
#define udd_micro_frame_number() \
(Rd_bitfield(UOTGHS->UOTGHS_DEVFNUM, (UOTGHS_DEVFNUM_FNUM_Msk|UOTGHS_DEVFNUM_MFNUM_Msk)))
//! @}
//! Manage suspend event
//! @{
#define udd_enable_suspend_interrupt() (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_SUSPES)
#define udd_disable_suspend_interrupt() (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_SUSPEC)
#define Is_udd_suspend_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_SUSPE))
#define udd_ack_suspend() (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVICR_SUSPC)
#define udd_raise_suspend() (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_SUSPS)
#define Is_udd_suspend() (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_SUSP))
//! @}
//! @}
//! @name UOTGHS device address control
//! These macros manage the UOTGHS Device address.
//! @{
//! enables USB device address
#define udd_enable_address() (Set_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_ADDEN))
//! disables USB device address
#define udd_disable_address() (Clr_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_ADDEN))
#define Is_udd_address_enabled() (Tst_bits(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_ADDEN))
//! configures the USB device address
#define udd_configure_address(addr) (Wr_bitfield(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_UADD_Msk, addr))
//! gets the currently configured USB device address
#define udd_get_configured_address() (Rd_bitfield(UOTGHS->UOTGHS_DEVCTRL, UOTGHS_DEVCTRL_UADD_Msk))
//! @}
//! @name UOTGHS Device endpoint drivers
//! These macros manage the common features of the endpoints.
//! @{
//! Generic macro for UOTGHS registers that can be arrayed
//! @{
#define UOTGHS_ARRAY(reg,index) ((&(UOTGHS->reg))[(index)])
//! @}
//! @name UOTGHS Device endpoint configuration
//! @{
//! enables the selected endpoint
#define udd_enable_endpoint(ep) (Set_bits(UOTGHS->UOTGHS_DEVEPT, UOTGHS_DEVEPT_EPEN0 << (ep)))
//! disables the selected endpoint
#define udd_disable_endpoint(ep) (Clr_bits(UOTGHS->UOTGHS_DEVEPT, UOTGHS_DEVEPT_EPEN0 << (ep)))
//! tests if the selected endpoint is enabled
#define Is_udd_endpoint_enabled(ep) (Tst_bits(UOTGHS->UOTGHS_DEVEPT, UOTGHS_DEVEPT_EPEN0 << (ep)))
//! resets the selected endpoint
#define udd_reset_endpoint(ep) \
do { \
Set_bits(UOTGHS->UOTGHS_DEVEPT, UOTGHS_DEVEPT_EPRST0 << (ep)); \
Clr_bits(UOTGHS->UOTGHS_DEVEPT, UOTGHS_DEVEPT_EPRST0 << (ep)); \
} while (0)
//! Tests if the selected endpoint is being reset
#define Is_udd_resetting_endpoint(ep) (Tst_bits(UOTGHS->UOTGHS_DEVEPT, UOTGHS_DEVEPT_EPRST0 << (ep)))
//! Configures the selected endpoint type
#define udd_configure_endpoint_type(ep, type) (Wr_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPTYPE_Msk, type))
//! Gets the configured selected endpoint type
#define udd_get_endpoint_type(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPTYPE_Msk))
//! Enables the bank autoswitch for the selected endpoint
#define udd_enable_endpoint_bank_autoswitch(ep) (Set_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_AUTOSW))
//! Disables the bank autoswitch for the selected endpoint
#define udd_disable_endpoint_bank_autoswitch(ep) (Clr_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_AUTOSW))
#define Is_udd_endpoint_bank_autoswitch_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_AUTOSW))
//! Configures the selected endpoint direction
#define udd_configure_endpoint_direction(ep, dir) (Wr_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPDIR, dir))
//! Gets the configured selected endpoint direction
#define udd_get_endpoint_direction(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPDIR))
#define Is_udd_endpoint_in(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPDIR))
//! Bounds given integer size to allowed range and rounds it up to the nearest
//! available greater size, then applies register format of UOTGHS controller
//! for endpoint size bit-field.
#undef udd_format_endpoint_size
#define udd_format_endpoint_size(size) (32 - clz(((uint32_t)min(max(size, 8), 1024) << 1) - 1) - 1 - 3)
//! Configures the selected endpoint size
#define udd_configure_endpoint_size(ep, size) (Wr_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPSIZE_Msk, udd_format_endpoint_size(size)))
//! Gets the configured selected endpoint size
#define udd_get_endpoint_size(ep) (8 << Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPSIZE_Msk))
//! Configures the selected endpoint number of banks
#define udd_configure_endpoint_bank(ep, bank) (Wr_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPBK_Msk, bank))
//! Gets the configured selected endpoint number of banks
#define udd_get_endpoint_bank(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPBK_Msk)+1)
//! Allocates the configuration selected endpoint in DPRAM memory
#define udd_allocate_memory(ep) (Set_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_ALLOC))
//! un-allocates the configuration selected endpoint in DPRAM memory
#define udd_unallocate_memory(ep) (Clr_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_ALLOC))
#define Is_udd_memory_allocated(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_ALLOC))
//! Configures selected endpoint in one step
#define udd_configure_endpoint(ep, type, dir, size, bank) (\
Wr_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTCFG[0], ep), UOTGHS_DEVEPTCFG_EPTYPE_Msk |\
UOTGHS_DEVEPTCFG_EPDIR |\
UOTGHS_DEVEPTCFG_EPSIZE_Msk |\
UOTGHS_DEVEPTCFG_EPBK_Msk , \
(((uint32_t)(type) << UOTGHS_DEVEPTCFG_EPTYPE_Pos) & UOTGHS_DEVEPTCFG_EPTYPE_Msk) |\
(((uint32_t)(dir ) << UOTGHS_DEVEPTCFG_EPDIR_Pos ) & UOTGHS_DEVEPTCFG_EPDIR) |\
( (uint32_t)udd_format_endpoint_size(size) << UOTGHS_DEVEPTCFG_EPSIZE_Pos) |\
(((uint32_t)(bank) << UOTGHS_DEVEPTCFG_EPBK_Pos) & UOTGHS_DEVEPTCFG_EPBK_Msk))\
)
//! Tests if current endpoint is configured
#define Is_udd_endpoint_configured(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_CFGOK))
//! Returns the control direction
#define udd_control_direction() (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], EP_CONTROL), UOTGHS_DEVEPTISR_CTRLDIR))
//! Resets the data toggle sequence
#define udd_reset_data_toggle(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_RSTDTS)
//! Tests if the data toggle sequence is being reset
#define Is_udd_data_toggle_reset(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_RSTDT))
//! Returns data toggle
#define udd_data_toggle(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_DTSEQ_Msk))
//! @}
//! @name UOTGHS Device control endpoint
//! These macros control the endpoints.
//! @{
//! @name UOTGHS Device control endpoint interrupts
//! These macros control the endpoints interrupts.
//! @{
//! Enables the selected endpoint interrupt
#define udd_enable_endpoint_interrupt(ep) (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_PEP_0 << (ep))
//! Disables the selected endpoint interrupt
#define udd_disable_endpoint_interrupt(ep) (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_PEP_0 << (ep))
//! Tests if the selected endpoint interrupt is enabled
#define Is_udd_endpoint_interrupt_enabled(ep) (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_PEP_0 << (ep)))
//! Tests if an interrupt is triggered by the selected endpoint
#define Is_udd_endpoint_interrupt(ep) (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_PEP_0 << (ep)))
//! Returns the lowest endpoint number generating an endpoint interrupt or MAX_PEP_NB if none
#define udd_get_interrupt_endpoint_number() (ctz(((UOTGHS->UOTGHS_DEVISR >> UOTGHS_DEVISR_PEP_Pos) & \
(UOTGHS->UOTGHS_DEVIMR >> UOTGHS_DEVIMR_PEP_Pos)) | \
(1 << MAX_PEP_NB)))
#define UOTGHS_DEVISR_PEP_Pos 12
#define UOTGHS_DEVIMR_PEP_Pos 12
//! @}
//! @name UOTGHS Device control endpoint errors
//! These macros control the endpoint errors.
//! @{
//! Enables the STALL handshake
#define udd_enable_stall_handshake(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_STALLRQS)
//! Disables the STALL handshake
#define udd_disable_stall_handshake(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_STALLRQC)
//! Tests if STALL handshake request is running
#define Is_udd_endpoint_stall_requested(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_STALLRQ))
//! Tests if STALL sent
#define Is_udd_stall(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_STALLEDI))
//! ACKs STALL sent
#define udd_ack_stall(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_STALLEDIC)
//! Raises STALL sent
#define udd_raise_stall(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_STALLEDIS)
//! Enables STALL sent interrupt
#define udd_enable_stall_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_STALLEDES)
//! Disables STALL sent interrupt
#define udd_disable_stall_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_STALLEDEC)
//! Tests if STALL sent interrupt is enabled
#define Is_udd_stall_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_STALLEDE))
//! Tests if NAK OUT received
#define Is_udd_nak_out(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_NAKOUTI))
//! ACKs NAK OUT received
#define udd_ack_nak_out(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_NAKOUTIC)
//! Raises NAK OUT received
#define udd_raise_nak_out(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_NAKOUTIS)
//! Enables NAK OUT interrupt
#define udd_enable_nak_out_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_NAKOUTES)
//! Disables NAK OUT interrupt
#define udd_disable_nak_out_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_NAKOUTEC)
//! Tests if NAK OUT interrupt is enabled
#define Is_udd_nak_out_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_NAKOUTE))
//! Tests if NAK IN received
#define Is_udd_nak_in(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_NAKINI))
//! ACKs NAK IN received
#define udd_ack_nak_in(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_NAKINIC)
//! Raises NAK IN received
#define udd_raise_nak_in(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_NAKINIS)
//! Enables NAK IN interrupt
#define udd_enable_nak_in_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_NAKINES)
//! Disables NAK IN interrupt
#define udd_disable_nak_in_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_NAKINEC)
//! Tests if NAK IN interrupt is enabled
#define Is_udd_nak_in_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_NAKINE))
//! ACKs endpoint isochronous overflow interrupt
#define udd_ack_overflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_OVERFIC)
//! Raises endpoint isochronous overflow interrupt
#define udd_raise_overflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_OVERFIS)
//! Tests if an overflow occurs
#define Is_udd_overflow(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_OVERFI))
//! Enables overflow interrupt
#define udd_enable_overflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_OVERFES)
//! Disables overflow interrupt
#define udd_disable_overflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_OVERFEC)
//! Tests if overflow interrupt is enabled
#define Is_udd_overflow_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_OVERFE))
//! ACKs endpoint isochronous underflow interrupt
#define udd_ack_underflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_UNDERFIC)
//! Raises endpoint isochronous underflow interrupt
#define udd_raise_underflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_UNDERFIS)
//! Tests if an underflow occurs
#define Is_udd_underflow(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_UNDERFI))
//! Enables underflow interrupt
#define udd_enable_underflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_UNDERFES)
//! Disables underflow interrupt
#define udd_disable_underflow_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_UNDERFEC)
//! Tests if underflow interrupt is enabled
#define Is_udd_underflow_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_UNDERFE))
//! Tests if CRC ERROR ISO OUT detected
#define Is_udd_crc_error(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_CRCERRI))
//! ACKs CRC ERROR ISO OUT detected
#define udd_ack_crc_error(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_CRCERRIC)
//! Raises CRC ERROR ISO OUT detected
#define udd_raise_crc_error(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_CRCERRIS)
//! Enables CRC ERROR ISO OUT detected interrupt
#define udd_enable_crc_error_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_CRCERRES)
//! Disables CRC ERROR ISO OUT detected interrupt
#define udd_disable_crc_error_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_CRCERREC)
//! Tests if CRC ERROR ISO OUT detected interrupt is enabled
#define Is_udd_crc_error_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_CRCERRE))
//! @}
//! @name UOTGHS Device control endpoint transfer
//! These macros control the endpoint transfer.
//! @{
//! Tests if endpoint read allowed
#define Is_udd_read_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_RWALL))
//! Tests if endpoint write allowed
#define Is_udd_write_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_RWALL))
//! Returns the byte count
#define udd_byte_count(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_BYCT_Msk))
//! Clears FIFOCON bit
#define udd_ack_fifocon(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_FIFOCONC)
//! Tests if FIFOCON bit set
#define Is_udd_fifocon(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_FIFOCON))
//! Returns the number of busy banks
#define udd_nb_busy_bank(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_NBUSYBK_Msk))
//! Returns the number of the current bank
#define udd_current_bank(ep) (Rd_bitfield(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_CURRBK_Msk))
//! Kills last bank
#define udd_kill_last_in_bank(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_KILLBKS)
#define Is_udd_kill_last(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_KILLBK))
//! Tests if last bank killed
#define Is_udd_last_in_bank_killed(ep) (!Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_KILLBK))
//! Forces all banks full (OUT) or free (IN) interrupt
#define udd_force_bank_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_NBUSYBKS)
//! Unforces all banks full (OUT) or free (IN) interrupt
#define udd_unforce_bank_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_NBUSYBKS)
//! Enables all banks full (OUT) or free (IN) interrupt
#define udd_enable_bank_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_NBUSYBKES)
//! Disables all banks full (OUT) or free (IN) interrupt
#define udd_disable_bank_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_NBUSYBKEC)
//! Tests if all banks full (OUT) or free (IN) interrupt enabled
#define Is_udd_bank_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_NBUSYBKE))
//! Tests if SHORT PACKET received
#define Is_udd_short_packet(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_SHORTPACKET))
//! ACKs SHORT PACKET received
#define udd_ack_short_packet(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_SHORTPACKETC)
//! Raises SHORT PACKET received
#define udd_raise_short_packet(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_SHORTPACKETS)
//! Enables SHORT PACKET received interrupt
#define udd_enable_short_packet_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_SHORTPACKETES)
//! Disables SHORT PACKET received interrupt
#define udd_disable_short_packet_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_SHORTPACKETEC)
//! Tests if SHORT PACKET received interrupt is enabled
#define Is_udd_short_packet_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_SHORTPACKETE))
//! Tests if SETUP received
#define Is_udd_setup_received(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_RXSTPI))
//! ACKs SETUP received
#define udd_ack_setup_received(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_RXSTPIC)
//! Raises SETUP received
#define udd_raise_setup_received(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_RXSTPIS)
//! Enables SETUP received interrupt
#define udd_enable_setup_received_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_RXSTPES)
//! Disables SETUP received interrupt
#define udd_disable_setup_received_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_RXSTPEC)
//! Tests if SETUP received interrupt is enabled
#define Is_udd_setup_received_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_RXSTPE))
//! Tests if OUT received
#define Is_udd_out_received(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_RXOUTI))
//! ACKs OUT received
#define udd_ack_out_received(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_RXOUTIC)
//! Raises OUT received
#define udd_raise_out_received(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_RXOUTIS)
//! Enables OUT received interrupt
#define udd_enable_out_received_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_RXOUTES)
//! Disables OUT received interrupt
#define udd_disable_out_received_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_RXOUTEC)
//! Tests if OUT received interrupt is enabled
#define Is_udd_out_received_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_RXOUTE))
//! Tests if IN sending
#define Is_udd_in_send(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTISR[0], ep), UOTGHS_DEVEPTISR_TXINI))
//! ACKs IN sending
#define udd_ack_in_send(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTICR[0], ep) = UOTGHS_DEVEPTICR_TXINIC)
//! Raises IN sending
#define udd_raise_in_send(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIFR[0], ep) = UOTGHS_DEVEPTIFR_TXINIS)
//! Enables IN sending interrupt
#define udd_enable_in_send_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0], ep) = UOTGHS_DEVEPTIER_TXINES)
//! Disables IN sending interrupt
#define udd_disable_in_send_interrupt(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0], ep) = UOTGHS_DEVEPTIDR_TXINEC)
//! Tests if IN sending interrupt is enabled
#define Is_udd_in_send_interrupt_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0], ep), UOTGHS_DEVEPTIMR_TXINE))
//! Get 64-, 32-, 16- or 8-bit access to FIFO data register of selected endpoint.
//! @param ep Endpoint of which to access FIFO data register
//! @param scale Data scale in bits: 64, 32, 16 or 8
//! @return Volatile 64-, 32-, 16- or 8-bit data pointer to FIFO data register
//! @warning It is up to the user of this macro to make sure that all accesses
//! are aligned with their natural boundaries except 64-bit accesses which
//! require only 32-bit alignment.
//! @warning It is up to the user of this macro to make sure that used HSB
//! addresses are identical to the DPRAM internal pointer modulo 32 bits.
#define udd_get_endpoint_fifo_access(ep, scale) \
(((volatile TPASTE2(U, scale) (*)[0x8000 / ((scale) / 8)])UOTGHS_RAM_ADDR)[(ep)])
//! @name UOTGHS endpoint DMA drivers
//! These macros manage the common features of the endpoint DMA channels.
//! @{
//! Maximum transfer size on USB DMA
#define UDD_ENDPOINT_MAX_TRANS 0x10000
//! Enables the disabling of HDMA requests by endpoint interrupts
#define udd_enable_endpoint_int_dis_hdma_req(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIER[0](ep) = UOTGHS_DEVEPTIER_EPDISHDMAS)
//! Disables the disabling of HDMA requests by endpoint interrupts
#define udd_disable_endpoint_int_dis_hdma_req(ep) (UOTGHS_ARRAY(UOTGHS_DEVEPTIDR[0](ep) = UOTGHS_DEVEPTIDR_EPDISHDMAC)
//! Tests if the disabling of HDMA requests by endpoint interrupts is enabled
#define Is_udd_endpoint_int_dis_hdma_req_enabled(ep) (Tst_bits(UOTGHS_ARRAY(UOTGHS_DEVEPTIMR[0](ep), UOTGHS_DEVEPTIMR_EPDISHDMA))
//! Raises the selected endpoint DMA channel interrupt
#define udd_raise_endpoint_dma_interrupt(ep) (UOTGHS->UOTGHS_DEVIFR = UOTGHS_DEVIFR_DMA_1 << ((ep) - 1))
//! Raises the selected endpoint DMA channel interrupt
#define udd_clear_endpoint_dma_interrupt(ep) (UOTGHS->UOTGHS_DEVICR = UOTGHS_DEVISR_DMA_1 << ((ep) - 1))
//! Tests if an interrupt is triggered by the selected endpoint DMA channel
#define Is_udd_endpoint_dma_interrupt(ep) (Tst_bits(UOTGHS->UOTGHS_DEVISR, UOTGHS_DEVISR_DMA_1 << ((ep) - 1)))
//! Enables the selected endpoint DMA channel interrupt
#define udd_enable_endpoint_dma_interrupt(ep) (UOTGHS->UOTGHS_DEVIER = UOTGHS_DEVIER_DMA_1 << ((ep) - 1))
//! Disables the selected endpoint DMA channel interrupt
#define udd_disable_endpoint_dma_interrupt(ep) (UOTGHS->UOTGHS_DEVIDR = UOTGHS_DEVIDR_DMA_1 << ((ep) - 1))
//! Tests if the selected endpoint DMA channel interrupt is enabled
#define Is_udd_endpoint_dma_interrupt_enabled(ep) (Tst_bits(UOTGHS->UOTGHS_DEVIMR, UOTGHS_DEVIMR_DMA_1 << ((ep) - 1)))
//! Access points to the UOTGHS device DMA memory map with arrayed registers
//! @{
//! Structure for DMA next descriptor register
typedef struct {
uint32_t *NXT_DSC_ADD;
} uotghs_dma_nextdesc_t;
//! Structure for DMA control register
typedef struct {
uint32_t CHANN_ENB:1,
LDNXT_DSC:1,
END_TR_EN:1,
END_B_EN:1,
END_TR_IT:1,
END_BUFFIT:1,
DESC_LD_IT:1,
BUST_LCK:1,
reserved:8,
BUFF_LENGTH:16;
} uotghs_dma_control_t;
//! Structure for DMA status register
typedef struct {
uint32_t CHANN_ENB:1,
CHANN_ACT:1,
reserved0:2,
END_TR_ST:1,
END_BF_ST:1,
DESC_LDST:1,
reserved1:9,
BUFF_COUNT:16;
} uotghs_dma_status_t;
//! Structure for DMA descriptor
typedef struct {
union {
uint32_t nextdesc;
uotghs_dma_nextdesc_t NEXTDESC;
};
uint32_t addr;
union {
uint32_t control;
uotghs_dma_control_t CONTROL;
};
uint32_t reserved;
} sam_uotghs_dmadesc_t, uotghs_dmadesc_t;
//! Structure for DMA registers in a channel
typedef struct {
union {
uint32_t nextdesc;
uotghs_dma_nextdesc_t NEXTDESC;
};
uint32_t addr;
union {
uint32_t control;
uotghs_dma_control_t CONTROL;
};
union {
unsigned long status;
uotghs_dma_status_t STATUS;
};
} sam_uotghs_dmach_t, uotghs_dmach_t;
//! DMA channel control command
#define UDD_ENDPOINT_DMA_STOP_NOW (0)
#define UDD_ENDPOINT_DMA_RUN_AND_STOP (UOTGHS_DEVDMACONTROL_CHANN_ENB)
#define UDD_ENDPOINT_DMA_LOAD_NEXT_DESC (UOTGHS_DEVDMACONTROL_LDNXT_DSC)
#define UDD_ENDPOINT_DMA_RUN_AND_LINK (UOTGHS_DEVDMACONTROL_CHANN_ENB|UOTGHS_DEVDMACONTROL_LDNXT_DSC)
//! Structure for DMA registers
#define UOTGHS_UDDMA_ARRAY(ep) (((volatile uotghs_dmach_t *)UOTGHS->UOTGHS_DEVDMA)[(ep) - 1])
//! Set control desc to selected endpoint DMA channel
#define udd_endpoint_dma_set_control(ep,desc) (UOTGHS_UDDMA_ARRAY(ep).control = desc)
//! Get control desc to selected endpoint DMA channel
#define udd_endpoint_dma_get_control(ep) (UOTGHS_UDDMA_ARRAY(ep).control)
//! Set RAM address to selected endpoint DMA channel
#define udd_endpoint_dma_set_addr(ep,add) (UOTGHS_UDDMA_ARRAY(ep).addr = add)
//! Get status to selected endpoint DMA channel
#define udd_endpoint_dma_get_status(ep) (UOTGHS_UDDMA_ARRAY(ep).status)
//! @}
//! @}
//! @}
//! @}
//! @}
//! @}
/// @cond 0
/**INDENT-OFF**/
#ifdef __cplusplus
}
#endif
/**INDENT-ON**/
/// @endcond
#endif /* UOTGHS_DEVICE_H_INCLUDED */

View File

@ -0,0 +1,241 @@
/**
* \file
*
* \brief USB OTG Driver for UOTGHS.
*
* Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef UOTGHS_OTG_H_INCLUDED
#define UOTGHS_OTG_H_INCLUDED
#include "compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
//! \ingroup usb_group
//! \defgroup otg_group UOTGHS OTG Driver
//! UOTGHS low-level driver for OTG features
//!
//! @{
/**
* \brief Initialize the dual role
* This function is implemented in uotghs_host.c file.
*
* \return \c true if the ID pin management has been started, otherwise \c false.
*/
bool otg_dual_enable(void);
/**
* \brief Uninitialize the dual role
* This function is implemented in uotghs_host.c file.
*/
void otg_dual_disable(void);
//! @name UOTGHS OTG ID pin management
//! The ID pin come from the USB OTG connector (A and B receptable) and
//! allows to select the USB mode host or device.
//! The UOTGHS hardware can manage it automatically. This feature is optional.
//! When USB_ID_GPIO is defined (in board.h), this feature is enabled.
//!
//! @{
//! Enable external OTG_ID pin (listened to by USB)
#define otg_enable_id_pin() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIDE))
//! Disable external OTG_ID pin (ignored by USB)
#define otg_disable_id_pin() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIDE))
//! Test if external OTG_ID pin enabled (listened to by USB)
#define Is_otg_id_pin_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIDE))
//! Disable external OTG_ID pin and force device mode
#define otg_force_device_mode() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIMOD), otg_disable_id_pin())
//! Test if device mode is forced
#define Is_otg_device_mode_forced() (!Is_otg_id_pin_enabled() && Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIMOD))
//! Disable external OTG_ID pin and force host mode
#define otg_force_host_mode() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIMOD), otg_disable_id_pin())
//! Test if host mode is forced
#define Is_otg_host_mode_forced() (!Is_otg_id_pin_enabled() && !Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UIMOD))
//! @name UOTGHS OTG ID pin interrupt management
//! These macros manage the ID pin interrupt
//! @{
#define otg_enable_id_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_IDTE))
#define otg_disable_id_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_IDTE))
#define Is_otg_id_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_IDTE))
#define Is_otg_id_device() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_ID))
#define Is_otg_id_host() (!Is_otg_id_device())
#define otg_ack_id_transition() (UOTGHS->UOTGHS_SCR = UOTGHS_SCR_IDTIC)
#define otg_raise_id_transition() (UOTGHS->UOTGHS_SFR = UOTGHS_SFR_IDTIS)
#define Is_otg_id_transition() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_IDTI))
//! @}
//! @}
//! @name OTG Vbus management
//! @{
#define otg_enable_vbus_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSTE))
#define otg_disable_vbus_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSTE))
#define Is_otg_vbus_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSTE))
#define Is_otg_vbus_high() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBUS))
#define Is_otg_vbus_low() (!Is_otg_vbus_high())
#define otg_ack_vbus_transition() (UOTGHS->UOTGHS_SCR = UOTGHS_SCR_VBUSTIC)
#define otg_raise_vbus_transition() (UOTGHS->UOTGHS_SFR = UOTGHS_SFR_VBUSTIS)
#define Is_otg_vbus_transition() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBUSTI))
//! @}
//! @name UOTGHS OTG main management
//! These macros allows to enable/disable pad and UOTGHS hardware
//! @{
//! Reset USB macro
#define otg_reset() \
do { \
UOTGHS->UOTGHS_CTRL = 0; \
while( UOTGHS->UOTGHS_SR & 0x3FFF) {\
UOTGHS->UOTGHS_SCR = 0xFFFFFFFF;\
} \
} while (0)
//! Enable USB macro
#define otg_enable() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_USBE))
//! Disable USB macro
#define otg_disable() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_USBE))
#define Is_otg_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_USBE))
//! Enable OTG pad
#define otg_enable_pad() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_OTGPADE))
//! Disable OTG pad
#define otg_disable_pad() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_OTGPADE))
#define Is_otg_pad_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_OTGPADE))
//! Check Clock Usable
//! For parts with HS feature, this one corresponding at UTMI clock
#define Is_otg_clock_usable() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_CLKUSABLE))
//! Stop (freeze) internal USB clock
#define otg_freeze_clock() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_FRZCLK))
#define otg_unfreeze_clock() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_FRZCLK))
#define Is_otg_clock_frozen() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_FRZCLK))
//! Configure time-out of specified OTG timer
#define otg_configure_timeout(timer, timeout) (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\
Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\
Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk, timeout),\
Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK))
//! Get configured time-out of specified OTG timer
#define otg_get_timeout(timer) (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\
Wr_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMPAGE_Msk, timer),\
Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_UNLOCK),\
Rd_bitfield(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_TIMVALUE_Msk))
//! Get the dual-role device state of the internal USB finite state machine of the UOTGHS controller
#define otg_get_fsm_drd_state() (Rd_bitfield(UOTGHS->UOTGHS_FSM, UOTGHS_FSM_DRDSTATE_Msk))
#define Is_otg_a_suspend() (4==otg_get_fsm_drd_state())
#define Is_otg_a_wait_vrise() (1==otg_get_fsm_drd_state())
//! @}
//! @name UOTGHS OTG hardware protocol
//! These macros manages the hardware OTG protocol
//! @{
//! Initiates a Host negotiation Protocol
#define otg_device_initiate_hnp() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPREQ))
//! Accepts a Host negotiation Protocol
#define otg_host_accept_hnp() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPREQ))
//! Rejects a Host negotiation Protocol
#define otg_host_reject_hnp() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPREQ))
//! initiates a Session Request Protocol
#define otg_device_initiate_srp() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPREQ))
//! Selects VBus as SRP method
#define otg_select_vbus_srp_method() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPSEL))
#define Is_otg_vbus_srp_method_selected() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPSEL))
//! Selects data line as SRP method
#define otg_select_data_srp_method() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPSEL))
#define Is_otg_data_srp_method_selected() (!Is_otg_vbus_srp_method_selected())
//! Tests if a HNP occurs
#define Is_otg_hnp() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPREQ))
//! Tests if a SRP from device occurs
#define Is_otg_device_srp() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPREQ))
//! Enables HNP error interrupt
#define otg_enable_hnp_error_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPERRE))
//! Disables HNP error interrupt
#define otg_disable_hnp_error_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPERRE))
#define Is_otg_hnp_error_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_HNPERRE))
//! ACKs HNP error interrupt
#define otg_ack_hnp_error_interrupt() (UOTGHS->UOTGHS_SCR = UOTGHS_SCR_HNPERRIC)
//! Raises HNP error interrupt
#define otg_raise_hnp_error_interrupt() (UOTGHS->UOTGHS_SFR = UOTGHS_SFR_HNPERRIS)
//! Tests if a HNP error occurs
#define Is_otg_hnp_error_interrupt() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_HNPERRI))
//! Enables role exchange interrupt
#define otg_enable_role_exchange_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_ROLEEXE))
//! Disables role exchange interrupt
#define otg_disable_role_exchange_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_ROLEEXE))
#define Is_otg_role_exchange_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_ROLEEXE))
//! ACKs role exchange interrupt
#define otg_ack_role_exchange_interrupt() (UOTGHS->UOTGHS_SCR = UOTGHS_SCR_ROLEEXIC)
//! Raises role exchange interrupt
#define otg_raise_role_exchange_interrupt() (UOTGHS->UOTGHS_SFR = UOTGHS_SFR_ROLEEXIS)
//! Tests if a role exchange occurs
#define Is_otg_role_exchange_interrupt() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_ROLEEXI))
//! Enables SRP interrupt
#define otg_enable_srp_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPE))
//! Disables SRP interrupt
#define otg_disable_srp_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPE))
#define Is_otg_srp_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_SRPE))
//! ACKs SRP interrupt
#define otg_ack_srp_interrupt() (UOTGHS->UOTGHS_SCR = UOTGHS_SCR_SRPIC)
//! Raises SRP interrupt
#define otg_raise_srp_interrupt() (UOTGHS->UOTGHS_SFR = UOTGHS_SFR_SRPIS)
//! Tests if a SRP occurs
#define Is_otg_srp_interrupt() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_SRPI))
//! @}
//! @}
#ifdef __cplusplus
}
#endif
#endif /* UOTGHS_OTG_H_INCLUDED */

View File

@ -0,0 +1,496 @@
/**
* \file
*
* \brief USB protocol definitions.
*
* This file contains the USB definitions and data structures provided by the
* USB 2.0 specification.
*
* Copyright (c) 2009-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef _USB_PROTOCOL_H_
#define _USB_PROTOCOL_H_
/**
* \ingroup usb_group
* \defgroup usb_protocol_group USB Protocol Definitions
*
* This module defines constants and data structures provided by the USB
* 2.0 specification.
*
* @{
*/
//! Value for field bcdUSB
#define USB_V2_0 0x0200 //!< USB Specification version 2.00
#define USB_V2_1 0x0201 //!< USB Specification version 2.01
/*! \name Generic definitions (Class, subclass and protocol)
*/
//! @{
#define NO_CLASS 0x00
#define CLASS_VENDOR_SPECIFIC 0xFF
#define NO_SUBCLASS 0x00
#define NO_PROTOCOL 0x00
//! @}
//! \name IAD (Interface Association Descriptor) constants
//! @{
#define CLASS_IAD 0xEF
#define SUB_CLASS_IAD 0x02
#define PROTOCOL_IAD 0x01
//! @}
/**
* \brief USB request data transfer direction (bmRequestType)
*/
#define USB_REQ_DIR_OUT (0<<7) //!< Host to device
#define USB_REQ_DIR_IN (1<<7) //!< Device to host
#define USB_REQ_DIR_MASK (1<<7) //!< Mask
/**
* \brief USB request types (bmRequestType)
*/
#define USB_REQ_TYPE_STANDARD (0<<5) //!< Standard request
#define USB_REQ_TYPE_CLASS (1<<5) //!< Class-specific request
#define USB_REQ_TYPE_VENDOR (2<<5) //!< Vendor-specific request
#define USB_REQ_TYPE_MASK (3<<5) //!< Mask
/**
* \brief USB recipient codes (bmRequestType)
*/
#define USB_REQ_RECIP_DEVICE (0<<0) //!< Recipient device
#define USB_REQ_RECIP_INTERFACE (1<<0) //!< Recipient interface
#define USB_REQ_RECIP_ENDPOINT (2<<0) //!< Recipient endpoint
#define USB_REQ_RECIP_OTHER (3<<0) //!< Recipient other
#define USB_REQ_RECIP_MASK (0x1F) //!< Mask
/**
* \brief Standard USB requests (bRequest)
*/
enum usb_reqid {
USB_REQ_GET_STATUS = 0,
USB_REQ_CLEAR_FEATURE = 1,
USB_REQ_SET_FEATURE = 3,
USB_REQ_SET_ADDRESS = 5,
USB_REQ_GET_DESCRIPTOR = 6,
USB_REQ_SET_DESCRIPTOR = 7,
USB_REQ_GET_CONFIGURATION = 8,
USB_REQ_SET_CONFIGURATION = 9,
USB_REQ_GET_INTERFACE = 10,
USB_REQ_SET_INTERFACE = 11,
USB_REQ_SYNCH_FRAME = 12,
};
/**
* \brief Standard USB device status flags
*
*/
enum usb_device_status {
USB_DEV_STATUS_BUS_POWERED = 0,
USB_DEV_STATUS_SELF_POWERED = 1,
USB_DEV_STATUS_REMOTEWAKEUP = 2
};
/**
* \brief Standard USB Interface status flags
*
*/
enum usb_interface_status {
USB_IFACE_STATUS_RESERVED = 0
};
/**
* \brief Standard USB endpoint status flags
*
*/
enum usb_endpoint_status {
USB_EP_STATUS_HALTED = 1,
};
/**
* \brief Standard USB device feature flags
*
* \note valid for SetFeature request.
*/
enum usb_device_feature {
USB_DEV_FEATURE_REMOTE_WAKEUP = 1, //!< Remote wakeup enabled
USB_DEV_FEATURE_TEST_MODE = 2, //!< USB test mode
USB_DEV_FEATURE_OTG_B_HNP_ENABLE = 3,
USB_DEV_FEATURE_OTG_A_HNP_SUPPORT = 4,
USB_DEV_FEATURE_OTG_A_ALT_HNP_SUPPORT = 5
};
/**
* \brief Test Mode possible on HS USB device
*
* \note valid for USB_DEV_FEATURE_TEST_MODE request.
*/
enum usb_device_hs_test_mode {
USB_DEV_TEST_MODE_J = 1,
USB_DEV_TEST_MODE_K = 2,
USB_DEV_TEST_MODE_SE0_NAK = 3,
USB_DEV_TEST_MODE_PACKET = 4,
USB_DEV_TEST_MODE_FORCE_ENABLE = 5,
};
/**
* \brief Standard USB endpoint feature/status flags
*/
enum usb_endpoint_feature {
USB_EP_FEATURE_HALT = 0,
};
/**
* \brief Standard USB Test Mode Selectors
*/
enum usb_test_mode_selector {
USB_TEST_J = 0x01,
USB_TEST_K = 0x02,
USB_TEST_SE0_NAK = 0x03,
USB_TEST_PACKET = 0x04,
USB_TEST_FORCE_ENABLE = 0x05,
};
/**
* \brief Standard USB descriptor types
*/
enum usb_descriptor_type {
USB_DT_DEVICE = 1,
USB_DT_CONFIGURATION = 2,
USB_DT_STRING = 3,
USB_DT_INTERFACE = 4,
USB_DT_ENDPOINT = 5,
USB_DT_DEVICE_QUALIFIER = 6,
USB_DT_OTHER_SPEED_CONFIGURATION = 7,
USB_DT_INTERFACE_POWER = 8,
USB_DT_OTG = 9,
USB_DT_IAD = 0x0B,
USB_DT_BOS = 0x0F,
USB_DT_DEVICE_CAPABILITY = 0x10,
};
/**
* \brief USB Device Capability types
*/
enum usb_capability_type {
USB_DC_USB20_EXTENSION = 0x02,
};
/**
* \brief USB Device Capability - USB 2.0 Extension
* To fill bmAttributes field of usb_capa_ext_desc_t structure.
*/
enum usb_capability_extension_attr {
USB_DC_EXT_LPM = 0x00000002,
};
#define HIRD_50_US 0
#define HIRD_125_US 1
#define HIRD_200_US 2
#define HIRD_275_US 3
#define HIRD_350_US 4
#define HIRD_425_US 5
#define HIRD_500_US 6
#define HIRD_575_US 7
#define HIRD_650_US 8
#define HIRD_725_US 9
#define HIRD_800_US 10
#define HIRD_875_US 11
#define HIRD_950_US 12
#define HIRD_1025_US 13
#define HIRD_1100_US 14
#define HIRD_1175_US 15
/** Fields definition from a LPM TOKEN */
#define USB_LPM_ATTRIBUT_BLINKSTATE_MASK (0xF << 0)
#define USB_LPM_ATTRIBUT_FIRD_MASK (0xF << 4)
#define USB_LPM_ATTRIBUT_REMOTEWAKE_MASK (1 << 8)
#define USB_LPM_ATTRIBUT_BLINKSTATE(value) ((value & 0xF) << 0)
#define USB_LPM_ATTRIBUT_FIRD(value) ((value & 0xF) << 4)
#define USB_LPM_ATTRIBUT_REMOTEWAKE(value) ((value & 1) << 8)
#define USB_LPM_ATTRIBUT_BLINKSTATE_L1 USB_LPM_ATTRIBUT_BLINKSTATE(1)
/**
* \brief Standard USB endpoint transfer types
*/
enum usb_ep_type {
USB_EP_TYPE_CONTROL = 0x00,
USB_EP_TYPE_ISOCHRONOUS = 0x01,
USB_EP_TYPE_BULK = 0x02,
USB_EP_TYPE_INTERRUPT = 0x03,
USB_EP_TYPE_MASK = 0x03,
};
/**
* \brief Standard USB language IDs for string descriptors
*/
enum usb_langid {
USB_LANGID_EN_US = 0x0409, //!< English (United States)
};
/**
* \brief Mask selecting the index part of an endpoint address
*/
#define USB_EP_ADDR_MASK 0x0F
//! \brief USB address identifier
typedef uint8_t usb_add_t;
/**
* \brief Endpoint transfer direction is IN
*/
#define USB_EP_DIR_IN 0x80
/**
* \brief Endpoint transfer direction is OUT
*/
#define USB_EP_DIR_OUT 0x00
//! \brief Endpoint identifier
typedef uint8_t usb_ep_t;
/**
* \brief Maximum length in bytes of a USB descriptor
*
* The maximum length of a USB descriptor is limited by the 8-bit
* bLength field.
*/
#define USB_MAX_DESC_LEN 255
/*
* 2-byte alignment requested for all USB structures.
*/
COMPILER_PACK_SET(1)
/**
* \brief A USB Device SETUP request
*
* The data payload of SETUP packets always follows this structure.
*/
typedef struct {
uint8_t bmRequestType;
uint8_t bRequest;
le16_t wValue;
le16_t wIndex;
le16_t wLength;
} usb_setup_req_t;
/**
* \brief Standard USB device descriptor structure
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
le16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
le16_t idVendor;
le16_t idProduct;
le16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} usb_dev_desc_t;
/**
* \brief Standard USB device qualifier descriptor structure
*
* This descriptor contains information about the device when running at
* the "other" speed (i.e. if the device is currently operating at high
* speed, this descriptor can be used to determine what would change if
* the device was operating at full speed.)
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
le16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint8_t bNumConfigurations;
uint8_t bReserved;
} usb_dev_qual_desc_t;
/**
* \brief USB Device BOS descriptor structure
*
* The BOS descriptor (Binary device Object Store) defines a root
* descriptor that is similar to the configuration descriptor, and is
* the base descriptor for accessing a family of related descriptors.
* A host can read a BOS descriptor and learn from the wTotalLength field
* the entire size of the device-level descriptor set, or it can read in
* the entire BOS descriptor set of device capabilities.
* The host accesses this descriptor using the GetDescriptor() request.
* The descriptor type in the GetDescriptor() request is set to BOS.
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
le16_t wTotalLength;
uint8_t bNumDeviceCaps;
} usb_dev_bos_desc_t;
/**
* \brief USB Device Capabilities - USB 2.0 Extension Descriptor structure
*
* Defines the set of USB 1.1-specific device level capabilities.
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDevCapabilityType;
le32_t bmAttributes;
} usb_dev_capa_ext_desc_t;
/**
* \brief USB Device LPM Descriptor structure
*
* The BOS descriptor and capabilities descriptors for LPM.
*/
typedef struct {
usb_dev_bos_desc_t bos;
usb_dev_capa_ext_desc_t capa_ext;
} usb_dev_lpm_desc_t;
/**
* \brief Standard USB Interface Association Descriptor structure
*/
typedef struct {
uint8_t bLength; //!< size of this descriptor in bytes
uint8_t bDescriptorType; //!< INTERFACE descriptor type
uint8_t bFirstInterface; //!< Number of interface
uint8_t bInterfaceCount; //!< value to select alternate setting
uint8_t bFunctionClass; //!< Class code assigned by the USB
uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB
uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB
uint8_t iFunction; //!< Index of string descriptor
} usb_association_desc_t;
/**
* \brief Standard USB configuration descriptor structure
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
le16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} usb_conf_desc_t;
#define USB_CONFIG_ATTR_MUST_SET (1 << 7) //!< Must always be set
#define USB_CONFIG_ATTR_BUS_POWERED (0 << 6) //!< Bus-powered
#define USB_CONFIG_ATTR_SELF_POWERED (1 << 6) //!< Self-powered
#define USB_CONFIG_ATTR_REMOTE_WAKEUP (1 << 5) //!< remote wakeup supported
#define USB_CONFIG_MAX_POWER(ma) (((ma) + 1) / 2) //!< Max power in mA
/**
* \brief Standard USB association descriptor structure
*/
typedef struct {
uint8_t bLength; //!< Size of this descriptor in bytes
uint8_t bDescriptorType; //!< Interface descriptor type
uint8_t bFirstInterface; //!< Number of interface
uint8_t bInterfaceCount; //!< value to select alternate setting
uint8_t bFunctionClass; //!< Class code assigned by the USB
uint8_t bFunctionSubClass; //!< Sub-class code assigned by the USB
uint8_t bFunctionProtocol; //!< Protocol code assigned by the USB
uint8_t iFunction; //!< Index of string descriptor
} usb_iad_desc_t;
/**
* \brief Standard USB interface descriptor structure
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} usb_iface_desc_t;
/**
* \brief Standard USB endpoint descriptor structure
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
le16_t wMaxPacketSize;
uint8_t bInterval;
} usb_ep_desc_t;
/**
* \brief A standard USB string descriptor structure
*/
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
} usb_str_desc_t;
typedef struct {
usb_str_desc_t desc;
le16_t string[1];
} usb_str_lgid_desc_t;
COMPILER_PACK_RESET()
//! @}
#endif /* _USB_PROTOCOL_H_ */

Some files were not shown because too many files have changed in this diff Show More