Coder Social home page Coder Social logo

avr-hal's People

Contributors

cecton avatar couchand avatar dalpil avatar dependabot[bot] avatar drmorr0 avatar eggtosch avatar enaut avatar explicite avatar gauteh avatar ghismary avatar jkristell avatar jonahbron avatar kallemooo avatar lperlaki avatar luigipiucco avatar marcuss2 avatar patryk27 avatar peter-simon avatar quentinmit avatar quinnfreedman avatar rahix avatar reinoutheeck avatar rhovian avatar rursprung avatar sepotvin avatar simonsso avatar tronje avatar urlordjames avatar west14 avatar wt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

avr-hal's Issues

Switch to embedded-hal 1.0.0

Not sure when is a good time to do this but it would be great to be an early adopter of the new traits :) They bring a lot of improvements to ergnomics and usability which would help the readability of downstream code a lot.

We do, however, have to consider that most drivers won't have updated yet so we have to be careful as to not become 100% incompatible. Maybe there is a possibility for a compat-shim layer or a cargo-feature to allow using the older version in parallel?

TTY not showing up on arduino Micro

Foreword

First off, I am a huge fan! Thank you for putting work into this project!
I am relatively new to Arduino programming, so this entire post might be a fault of of my own.

General info

  • Device: Arduino Micro
  • OS: Fedora 32, running linux kernel 5.5.6
  • I followed the Arduino Leonardo example, since the Arduino Micro shares the same microchip (ATmega32U4)

The issue at hand: Serial monitor unavailable

When I use Arduino IDE to flash a bare bones program to the arduino (Appendix 1 & 2) I get a tty device under /dev/ttyACM0 regardless of the program contents.

When I use avrdude to flash the rust program (Appendix 3 & 4) no tty device is created. I also checked /dev/ttyS0, it exists, but does not generate contents.

This means I am unable to view the output of the device since the serial monitor has nothing to connect to. I'm not sure what other diagnostics to perform, but I'm willing to supply more information if needed!

Thanks a bunch for creating this project, I can't wait to use it!

Appendices

Appendix 1: Code within arduino IDE

void setup() {
  
}

void loop() {
  delay(1);
}

Appendix 2: Arduino IDE and avrdude output

Spoiler: Arduino IDE with blank script: avrdude
/home/predator/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude -C/home/predator/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D -Uflash:w:/tmp/arduino_build_696973/DigitalReadSerial.ino.hex:i 

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/home/predator/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf"
         User configuration file is "/home/predator/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/ttyACM0
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
    Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.

Programmer supports the following devices:
    Device code: 0x44

avrdude: devcode selected: 0x44
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9587 (probably m32u4)
avrdude: reading input file "/tmp/arduino_build_696973/DigitalReadSerial.ino.hex"
avrdude: writing flash (3872 bytes):

Writing | ################################################## | 100% 0.37s

avrdude: 3872 bytes of flash written
avrdude: verifying flash memory against /tmp/arduino_build_696973/DigitalReadSerial.ino.hex:
avrdude: load data flash data from input file /tmp/arduino_build_696973/DigitalReadSerial.ino.hex:
avrdude: input file /tmp/arduino_build_696973/DigitalReadSerial.ino.hex contains 3872 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.16s

avrdude: verifying ...
avrdude: 3872 bytes of flash verified

avrdude done.  Thank you.

Appendix 3: avr-hal: my echo script, based on the example

#[arduino_leonardo::entry]
fn main() -> ! {
    let dp = arduino_leonardo::Peripherals::take().unwrap();

    // @Rahix I assumed these were the correct pins (identical to the Leonardo example), this might be wrong, but I don't know how to verify that.
    let mut pins = arduino_leonardo::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD, dp.PORTE);

    let mut serial: Usart1<MHz16, Floating> = arduino_leonardo::Serial::new(
        dp.USART1,
        pins.d0,
        pins.d1.into_output(&mut pins.ddr),
        57600,
    );

    let mut led: PB6<Output> = pins.d10.into_output(&pins.ddr);
    led.set_high().void_unwrap();

    ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").void_unwrap();
    loop {
        ufmt::uwriteln!(&mut serial, "HELLO?").void_unwrap();
        arduino_leonardo::delay_ms(500);
    }
}

Appendix 4: avr-hal + echo script, avrdude

Spoiler: avr-hal + echo script, avrdude

Executed with your modified script, to ensure the same avrdude is used with verbose output: /home/predator/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/bin/avrdude -C/home/predator/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf -v -patmega32u4 -cavr109 -P/dev/ttyACM0 -b57600 -D "-Uflash:w:$1:e"

avrdude: Version 6.3-20190619
         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
         Copyright (c) 2007-2014 Joerg Wunsch

         System wide configuration file is "/home/predator/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17/etc/avrdude.conf"
         User configuration file is "/home/predator/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/ttyACM0
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
         AVR Part                      : ATmega32U4
         Chip Erase delay              : 9000 us
         PAGEL                         : PD7
         BS2                           : PA0
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom        65    20     4    0 no       1024    4      0  9000  9000 0x00 0x00
           flash         65     6   128    0 yes     32768  128    256  4500  4500 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           efuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

         Programmer Type : butterfly
         Description     : Atmel AppNote AVR109 Boot Loader

Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
    Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.

Programmer supports the following devices:
    Device code: 0x44

avrdude: devcode selected: 0x44
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9587 (probably m32u4)
avrdude: reading input file "target/avr-atmega32u4/release/avr-example.elf"
avrdude: writing flash (516 bytes):

Writing | ################################################## | 100% 0.06s

avrdude: 516 bytes of flash written
avrdude: verifying flash memory against target/avr-atmega32u4/release/avr-example.elf:
avrdude: load data flash data from input file target/avr-atmega32u4/release/avr-example.elf:
avrdude: input file target/avr-atmega32u4/release/avr-example.elf contains 516 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.02s

avrdude: verifying ...
avrdude: 516 bytes of flash verified

avrdude done.  Thank you.

Cleanup target files

Notes to myself about what needs to happen:

  • Move all target files into a single top-level directory. Update all .cargo/config.tomls to point to the files in this place instead. -> This gets rid of the symlinks thus fixing #29.
  • Do this cleanup to all our target files as well.
  • Check remaining settings against current upstream defaults (after rust-lang/rust#74941)
  • Think about maybe adding infrastructure for automatically deriving the target files from upstream defaults to reduce maintenance burden.

Errors from ATMega32u4 chip

While trying to build on my fork (which revealed some bugs in my code fortunately), I'm seeing errors come from the atmega32u4 chip crate.

error[E0412]: cannot find type `PORTE` in module `crate::atmega32u4`
  --> chips/atmega32u4-hal/src/port.rs:14:30
   |
14 |         E(crate::atmega32u4::PORTE, porte, pine),
   |                              ^^^^^ help: a struct with a similar name exists: `PORTB`

error[E0412]: cannot find type `PORTF` in module `crate::atmega32u4`
  --> chips/atmega32u4-hal/src/port.rs:15:30
   |
15 |         F(crate::atmega32u4::PORTF, portf, pinf),
   |                              ^^^^^ help: a struct with a similar name exists: `PORTB`

error[E0412]: cannot find type `PORTE` in module `atmega32u4`
  --> chips/atmega32u4-hal/src/port.rs:87:38
   |
87 |         impl PortExt for atmega32u4::PORTE {
   |                                      ^^^^^ help: a struct with a similar name exists: `PORTB`

error[E0412]: cannot find type `PORTF` in module `atmega32u4`
   --> chips/atmega32u4-hal/src/port.rs:103:38
    |
103 |         impl PortExt for atmega32u4::PORTF {
    |                                      ^^^^^ help: a struct with a similar name exists: `PORTB`

error[E0412]: cannot find type `USART1` in module `crate::atmega32u4`
 --> chips/atmega32u4-hal/src/usart.rs:5:40
  |
5 |         peripheral: crate::atmega32u4::USART1,
  |                                        ^^^^^^ help: a struct with a similar name exists: `USART0`

error: aborting due to 5 previous errors

Are these something you'd like me to try to fix, or are these errors showing for some non-obvious user-error reason?

trait embedded_hal::blocking::spi::write::Default<u8> is not implemented for arduino_uno

Heya, me again!

I'm trying to glue some led strip driver code (apa102) to the arduino board code, which yielded the error:

trait embedded_hal::blocking::spi::write::Default<u8> is not implemented for `arduino_uno::spi::Spi<arduino_uno::atmega328p_hal::port::
mode::PullUp>

When I asked in Gitter it was suggested that this is a temporary hole, I could try to plug it. I assume it'd be a matter of pulling this:
https://github.com/rust-embedded/embedded-hal/blob/d81cf7cdb36d2214136891c7a6e0d45f9fe04723/src/blocking/spi.rs#L59
into avr-hal-generic::spi?

Support externally-pulled SPI

The current implementation demands that SCLK and MOSI be in mode::Output and MISO be in mode::Input<mode::PullUp> before creating the Spi. But the hardware would support more general bounds.

The input MISO could be floating, to allow for an external pull-up, and it seems this change can be made without any other code changes.

And while normal SPI operation is push-pull, it is occasionally configured as open-drain, which also seems to be supported by the hardware. The datasheets clearly state the output pins' pin directions are user-defined. Since I haven't found authoritative documentation on the matter and haven't set up a test bench, I'm reading between the lines a bit, but I interpret this to mean the SPI peripheral will output the signals by toggling the DDR rather than the pin. Perhaps real testing is needed before making code changes here.

Accurate PWM

The existing PWM implementation is fixed to 1kHz and uses the Fast PWM mode which isn't phase- nor frequency-correct. This is rather useless for applications like controlling a Servo where an exact frequency and duty-cycle are needed.

So, in addition to the Fast PWM implementation a seconds "correct" PWM implementation should be added which allows specifying the frequency + duty cycle exactly. Ideally, this should be based on the rate and duration primitives from embedded-time.

Open Questions:

  • How to select the prescaling? We could devise an algorithm to use the smallest clock-divider which still fits the frequency. This would, however make it entirely unobvious what precision the duty-cycle will have. Would good documentation help here? Or should the prescaler be selected manually instead?
  • Should the Duty type be a percentage or a duration?
  • Not all pins will be available with this "correct" PWM mode, because some of the timer peripherals aren't flexible enough for this (e.g. OCR0A is either used for PWM on OC0A, or as the timer period). How do we properly model this?

Runner support for macOS

Leonardo runner in macOS require some additional changes.

  1. numfmt installation brew install coreutils
  2. avrdude installation brew install avrdude
  3. avrdude conf location update
  4. avrdude: ser_open(): can't open device "/dev/ttyACM0": No such file or directory after first upload

@Rahix do you have any idea how we can improve this?

Add support for: SparkFun Qwiic Pro Micro - USB-C (ATmega32U4)

Shop page: https://www.sparkfun.com/products/15795
Datasheet: https://cdn.sparkfun.com/datasheets/Dev/Arduino/Boards/ATMega32U4.pdf
Addons: https://cdn.sparkfun.com/assets/learn_tutorials/1/2/1/SparkFunBoard_Addons_Jan_16.zip

As discussed it would be nice to update avr-hal with this board. I tested entirely using the leonardo crate and I couldn't find any difference between the Leonardo and this board.

Here is the pin file provided in the addons for this board (included in the zip file above):

/*
  pins_arduino.h - Pin definition functions for Arduino
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2007 David A. Mellis

  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., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
*/

#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <avr/pgmspace.h>

// Workaround for wrong definitions in "iom32u4.h".
// This should be fixed in the AVR toolchain.
#undef UHCON
#undef UHINT
#undef UHIEN
#undef UHADDR
#undef UHFNUM
#undef UHFNUML
#undef UHFNUMH
#undef UHFLEN
#undef UPINRQX
#undef UPINTX
#undef UPNUM
#undef UPRST
#undef UPCONX
#undef UPCFG0X
#undef UPCFG1X
#undef UPSTAX
#undef UPCFG2X
#undef UPIENX
#undef UPDATX
#undef TCCR2A
#undef WGM20
#undef WGM21
#undef COM2B0
#undef COM2B1
#undef COM2A0
#undef COM2A1
#undef TCCR2B
#undef CS20
#undef CS21
#undef CS22
#undef WGM22
#undef FOC2B
#undef FOC2A
#undef TCNT2
#undef TCNT2_0
#undef TCNT2_1
#undef TCNT2_2
#undef TCNT2_3
#undef TCNT2_4
#undef TCNT2_5
#undef TCNT2_6
#undef TCNT2_7
#undef OCR2A
#undef OCR2_0
#undef OCR2_1
#undef OCR2_2
#undef OCR2_3
#undef OCR2_4
#undef OCR2_5
#undef OCR2_6
#undef OCR2_7
#undef OCR2B
#undef OCR2_0
#undef OCR2_1
#undef OCR2_2
#undef OCR2_3
#undef OCR2_4
#undef OCR2_5
#undef OCR2_6
#undef OCR2_7

#define NUM_DIGITAL_PINS  31
#define NUM_ANALOG_INPUTS 12

#define TX_RX_LED_INIT  DDRD |= (1<<5), DDRB |= (1<<0)
#define TXLED0          PORTD |= (1<<5)
#define TXLED1          PORTD &= ~(1<<5)
#define RXLED0          PORTB |= (1<<0)
#define RXLED1          PORTB &= ~(1<<0)

static const uint8_t SDA = 2;
static const uint8_t SCL = 3;
#define LED_BUILTIN 13
#define LED_BUILTIN_RX 17					
#define LED_BUILTIN_TX 30

// Map SPI port to 'new' pins D14..D17
static const uint8_t SS   = 17;
static const uint8_t MOSI = 16;
static const uint8_t MISO = 14;
static const uint8_t SCK  = 15;

// Mapping of analog pins as digital I/O
// A6-A11 share with digital pins
static const uint8_t A0 = 18;
static const uint8_t A1 = 19;
static const uint8_t A2 = 20;
static const uint8_t A3 = 21;
static const uint8_t A4 = 22;
static const uint8_t A5 = 23;
static const uint8_t A6 = 24;   // D4
static const uint8_t A7 = 25;   // D6
static const uint8_t A8 = 26;   // D8
static const uint8_t A9 = 27;   // D9
static const uint8_t A10 = 28;  // D10
static const uint8_t A11 = 29;  // D12

#define digitalPinToPCICR(p)    ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCICR) : ((uint8_t *)0))
#define digitalPinToPCICRbit(p) 0
#define digitalPinToPCMSK(p)    ((((p) >= 8 && (p) <= 11) || ((p) >= 14 && (p) <= 17) || ((p) >= A8 && (p) <= A10)) ? (&PCMSK0) : ((uint8_t *)0))
#define digitalPinToPCMSKbit(p) ( ((p) >= 8 && (p) <= 11) ? (p) - 4 : ((p) == 14 ? 3 : ((p) == 15 ? 1 : ((p) == 16 ? 2 : ((p) == 17 ? 0 : (p - A8 + 4))))))

//  __AVR_ATmega32U4__ has an unusual mapping of pins to channels
extern const uint8_t PROGMEM analog_pin_to_channel_PGM[];
#define analogPinToChannel(P)  ( pgm_read_byte( analog_pin_to_channel_PGM + (P) ) )

#define digitalPinToInterrupt(p) ((p) == 0 ? 2 : ((p) == 1 ? 3 : ((p) == 2 ? 1 : ((p) == 3 ? 0 : ((p) == 7 ? 4 : NOT_AN_INTERRUPT)))))

#ifdef ARDUINO_MAIN

// On the Arduino board, digital pins are also used
// for the analog output (software PWM).  Analog input
// pins are a separate set.

// ATMEL ATMEGA32U4 / ARDUINO LEONARDO
//
// D0               PD2                 RXD1/INT2
// D1               PD3                 TXD1/INT3
// D2               PD1     SDA         SDA/INT1
// D3#              PD0     PWM8/SCL    OC0B/SCL/INT0
// D4       A6      PD4                 ADC8
// D5#              PC6     ???         OC3A/#OC4A
// D6#      A7      PD7     FastPWM     #OC4D/ADC10
// D7               PE6                 INT6/AIN0
//
// D8       A8      PB4                 ADC11/PCINT4
// D9#      A9      PB5     PWM16       OC1A/#OC4B/ADC12/PCINT5
// D10#     A10     PB6     PWM16       OC1B/0c4B/ADC13/PCINT6
// D11#             PB7     PWM8/16     0C0A/OC1C/#RTS/PCINT7
// D12      A11     PD6                 T1/#OC4D/ADC9
// D13#             PC7     PWM10       CLK0/OC4A
//
// A0       D18     PF7                 ADC7
// A1       D19     PF6                 ADC6
// A2       D20     PF5                 ADC5
// A3       D21     PF4                 ADC4
// A4       D22     PF1                 ADC1
// A5       D23     PF0                 ADC0
//
// New pins D14..D17 to map SPI port to digital pins
//
// MISO     D14     PB3                 MISO,PCINT3
// SCK      D15     PB1                 SCK,PCINT1
// MOSI     D16     PB2                 MOSI,PCINT2
// SS       D17     PB0                 RXLED,SS/PCINT0
//
// Connected LEDs on board for TX and RX
// TXLED    D30     PD5                 XCK1
// RXLED    D17     PB0
// HWB              PE2                 HWB

// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint16_t PROGMEM port_to_mode_PGM[] = {
    NOT_A_PORT,
    NOT_A_PORT,
    (uint16_t) &DDRB,
    (uint16_t) &DDRC,
    (uint16_t) &DDRD,
    (uint16_t) &DDRE,
    (uint16_t) &DDRF,
};

const uint16_t PROGMEM port_to_output_PGM[] = {
    NOT_A_PORT,
    NOT_A_PORT,
    (uint16_t) &PORTB,
    (uint16_t) &PORTC,
    (uint16_t) &PORTD,
    (uint16_t) &PORTE,
    (uint16_t) &PORTF,
};

const uint16_t PROGMEM port_to_input_PGM[] = {
    NOT_A_PORT,
    NOT_A_PORT,
    (uint16_t) &PINB,
    (uint16_t) &PINC,
    (uint16_t) &PIND,
    (uint16_t) &PINE,
    (uint16_t) &PINF,
};

const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
    PD, // D0 - PD2
    PD, // D1 - PD3
    PD, // D2 - PD1
    PD, // D3 - PD0
    PD, // D4 - PD4
    PC, // D5 - PC6
    PD, // D6 - PD7
    PE, // D7 - PE6
    
    PB, // D8 - PB4
    PB, // D9 - PB5
    PB, // D10 - PB6
    PB, // D11 - PB7
    PD, // D12 - PD6
    PC, // D13 - PC7
    
    PB, // D14 - MISO - PB3
    PB, // D15 - SCK - PB1
    PB, // D16 - MOSI - PB2
    PB, // D17 - SS - PB0
    
    PF, // D18 - A0 - PF7
    PF, // D19 - A1 - PF6
    PF, // D20 - A2 - PF5
    PF, // D21 - A3 - PF4
    PF, // D22 - A4 - PF1
    PF, // D23 - A5 - PF0
    
    PD, // D24 / PD5
    PD, // D25 / D6 - A7 - PD7
    PB, // D26 / D8 - A8 - PB4
    PB, // D27 / D9 - A9 - PB5
    PB, // D28 / D10 - A10 - PB6
    PD, // D29 / D12 - A11 - PD6
    PD, // D30 / TX Led - PD5
};

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
    _BV(2), // D0 - PD2
    _BV(3), // D1 - PD3
    _BV(1), // D2 - PD1
    _BV(0), // D3 - PD0
    _BV(4), // D4 - PD4
    _BV(6), // D5 - PC6
    _BV(7), // D6 - PD7
    _BV(6), // D7 - PE6
    
    _BV(4), // D8 - PB4
    _BV(5), // D9 - PB5
    _BV(6), // D10 - PB6
    _BV(7), // D11 - PB7
    _BV(6), // D12 - PD6
    _BV(7), // D13 - PC7
    
    _BV(3), // D14 - MISO - PB3
    _BV(1), // D15 - SCK - PB1
    _BV(2), // D16 - MOSI - PB2
    _BV(0), // D17 - SS - PB0
    
    _BV(7), // D18 - A0 - PF7
    _BV(6), // D19 - A1 - PF6
    _BV(5), // D20 - A2 - PF5
    _BV(4), // D21 - A3 - PF4
    _BV(1), // D22 - A4 - PF1
    _BV(0), // D23 - A5 - PF0
    
	  _BV(4), // D24 / D4 - A6 - PD4
    _BV(7), // D25 / D6 - A7 - PD7
    _BV(4), // D26 / D8 - A8 - PB4
    _BV(5), // D27 / D9 - A9 - PB5
    _BV(6), // D28 / D10 - A10 - PB6
    _BV(6), // D29 / D12 - A11 - PD6
    _BV(5), // D30 / TX Led - PD5
};

const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
    NOT_ON_TIMER,   
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    TIMER0B,        /* 3 */
    NOT_ON_TIMER,
    TIMER3A,        /* 5 */
    TIMER4D,        /* 6 */
    NOT_ON_TIMER,   
    
    NOT_ON_TIMER,   
    TIMER1A,        /* 9 */
    TIMER1B,        /* 10 */
    TIMER0A,        /* 11 */
    
    NOT_ON_TIMER,   
    TIMER4A,        /* 13 */
    
    NOT_ON_TIMER,   
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,

    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
    NOT_ON_TIMER,
};

const uint8_t PROGMEM analog_pin_to_channel_PGM[] = {
    7,  // A0               PF7                 ADC7
    6,  // A1               PF6                 ADC6    
    5,  // A2               PF5                 ADC5    
    4,  // A3               PF4                 ADC4
    1,  // A4               PF1                 ADC1    
    0,  // A5               PF0                 ADC0    
    8,  // A6       D4      PD4                 ADC8
    10, // A7       D6      PD7                 ADC10
    11, // A8       D8      PB4                 ADC11
    12, // A9       D9      PB5                 ADC12
    13, // A10      D10     PB6                 ADC13
    9   // A11      D12     PD6                 ADC9
};

#endif /* ARDUINO_MAIN */

// These serial port names are intended to allow libraries and architecture-neutral
// sketches to automatically default to the correct port name for a particular type
// of use.  For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
// the first hardware serial port whose RX/TX pins are not dedicated to another use.
//
// SERIAL_PORT_MONITOR        Port which normally prints to the Arduino Serial Monitor
//
// SERIAL_PORT_USBVIRTUAL     Port which is USB virtual serial
//
// SERIAL_PORT_LINUXBRIDGE    Port which connects to a Linux system via Bridge library
//
// SERIAL_PORT_HARDWARE       Hardware serial port, physical RX & TX pins.
//
// SERIAL_PORT_HARDWARE_OPEN  Hardware serial ports which are open for use.  Their RX & TX
//                            pins are NOT connected to anything by default.
#define SERIAL_PORT_MONITOR        Serial
#define SERIAL_PORT_USBVIRTUAL     Serial
#define SERIAL_PORT_HARDWARE       Serial1
#define SERIAL_PORT_HARDWARE_OPEN  Serial1

// Alias SerialUSB to Serial
#define SerialUSB SERIAL_PORT_USBVIRTUAL

#endif /* Pins_Arduino_h */

No messages shown over serial/UART

Apologies if this is a dumb question, or if there is a better place to ask these sorts of questions, but I copied and pasted the arduino uno serial example and successfully flashed it to my arduino uno, but I'm unable to see any of the "Hello from Arduino!" or the "Got {}" messages.

I'm on a mac and ran

screen /dev/tty.usbmodem144301 57600

But couldn't see any messages coming in while I was typing.

Is there an equivalent to the Serial.print with the normal C/C++ variant that Arduino uses?

Serial.begin(57600);
Serial.print("Some value");

When I run the same screen with something like that, I can at least see values coming in.

Remove "singlethread": true

In all the target JSON files, "singlethread": true is set. However, I don't believe that this worksโ€”interrupts can still cause problems, as an interrupt happening at the wrong place can interfere with the operation. The only operation that AVR can perform safely is an 8-bit read or write. All other operations require disabling interrupts.

Wrong link for atmega328p chip in README

The link should be in https://github.com/Rahix/avr-hal/blob/master/chips/atmega328p-hal but it's pointing to https://github.com/Rahix/avr-hal/blob/master/'./chips/atmega328p-hal

split out atmega328pb

Hello,

I couldn't get the atmega328pb hal running. So i splinted it out in a separate sub-crate at chips/atmega328pb-hal. i think my problems came from setting the correct feature but then using them under a different name in the code. Nethertheless i think it is more clean to have a separate hal for each chip. If you think so to I can open a pull request, but if you want to keep it the way it is feel free to just close my issue :).

here are my changes: https://github.com/fneddy/avr-hal/commit/7e175153ce8a7607678df128d42a2eacb5d58963 it still need some polishing i think, but i could get a LED and UART working.

SPI Support

As far as I can tell, avr-hal-generic (and by extension the chip implementations) do not support SPI. There is a trait for this in HAL. May/should I try to figure out how to implement that?

Need examples showing how to use timer interrupts : ISR : OCR: interrupt service routine: output compare register

BACKGROUND

I'm attempting to follow various examples for writing timer driven interrupt service routines in rust targeting the AVR...similar to these examples in arduino c:

https://www.instructables.com/id/Arduino-Timer-Interrupts/
https://circuitdigest.com/microcontroller-projects/arduino-timer-tutorial

EXAMPLE c CODE

In these examples, there is a stanza for setting the various registers to set this up. Here's an extract:

//set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);

Then these c examples show how to wire up an ISR:

ISR(TIMER1_COMPA_vect){...}

AVR-HAL rust CODE

In the avr-hal repo's various examples, I only see reference to the timer registers of tccr1b and tcnt1. Is this an oversight or is this because of some limitation on the platform? It would be really useful to see an example that included the other registers such as compare ocr1a and especially an example showing the use of an interrupt service routine like the common c ISR above.

Links:
Here's the example code I am following, though I've looked at all the avr-hal examples that include a timer:

  1. Create the timer
  2. Configure prescaling (TCCR1B)
  3. Reset/clear the timer (TCNT1)
  4. Is this TCNT1 read the equivalent of an output compare register (OCR)?

REQUEST

An example that sets up 2 different timers, say timer0 and timer1, and instantiates an ISR. I assume this would mean properly setting the ocr0a and ocr1a registers...h

I am happy to assist with documentation and more examples, but I need some direction/guidance here.

Crate Versioning

As avr-hal is made up of quite a few crates, decision needs to be made how versioning is handled. The two extremes would be

  1. All crates are versioned in lock-step and interdependencies are listed as =X.Y.Z to enforce the lock-step versioning.
  2. Releases and versions are managed on a per-crate basis.

Option 1. has the obvious drawback that a breaking change in any crate would lead to a major version bump for all crates. OTOH, Option 2. would mean a lot of effort to ensure no errors are made and any crate needing an update gets it. Especially breaking changes in the generic part are difficult to manage here ...

At first glance, I'm not a fan of either of those. Maybe there is some middle-ground that is acceptable?

Interrupt Semantics

From @peacememories in Rahix/avr-device#19:

I wonder... do you think we can encode semantics like โ€œwhen this interrupt fires the uart has incoming dataโ€ in the interrupts? Would that make sense? Why I would be interested in doing this: in c I would just start reading data from uart on an interrupt, but in rust Iโ€™d use read on the uart which (afaict) also Checks if there is actually data in the register. This is good for safety, but technically when the uart interrupt fires I have a guarantee that there is data available. Same for adc samples etc.

Timer-based Delay & CountDown

Right now, avr-hal only supports busy-loop delay which is bad for power-consumption and inaccurate with longer wait times. We should also add support for timer based delay and while working on that, also add implementations for the embedded-hal timer trait: CountDown

Maybe, along the same lines, an implementation of embedded_time::Clock could also be useful.

consider migrating to the new asm! syntax specified in RFC 2873

Hi!
I've been trying to following code example for atmega328p:

#![no_std]
#![no_main]
#![feature(proc_macro_hygiene)]

use arduino_leonardo::prelude::*;

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    let mut serial: arduino_leonardo::Serial<arduino_leonardo::hal::port::mode::Floating> = unsafe {
        core::mem::uninitialized()
    };

    ufmt::uwriteln!(&mut serial, "Firmware panic!\r");

    if let Some(loc) = info.location() {
        ufmt::uwriteln!(
            &mut serial,
            "  At {}:{}:{}\r",
            loc.file(),
            loc.line(),
            loc.column(),
        );
    }

    loop {}
}

#[no_mangle]
pub extern fn main() -> ! {
    let dp = arduino_leonardo::Peripherals::take().unwrap();

    let mut pins = arduino_leonardo::Pins::new(
        dp.PORTB,
        dp.PORTC,
        dp.PORTD,
        dp.PORTE,
    );

    let mut serial = arduino_leonardo::Serial::new(
        dp.USART1,
        pins.d0,
        pins.d1.into_output(&mut pins.ddr),
        57600,
    );

    ufmt::uwriteln!(&mut serial, "Hello from Arduino!\r").unwrap();
    // Panic messages cannot yet be captured because they rely on core::fmt
    // which is way too big for AVR
    panic!();
}

My Cargo.toml is the following

[package]
name = "sensor"
version = "0.1.0"
authors = ["Jรฉrรฉmie Drouet <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
panic-halt = "0.2.0"

[dependencies.arduino-leonardo]
path = ".../avr-hal/boards/arduino-leonardo"

[profile.dev]
panic = "abort"
codegen-units = 1
incremental = false
lto = true

[profile.release]
panic = "abort"
codegen-units = 1
debug = false
lto = true

I'm using rust sources from this PR and the blink example compiles well.

But when I try to use avr-hal, I get the following error.

error: the legacy LLVM-style asm! syntax is no longer supported
  --> /home/jdrouet/.cargo/git/checkouts/avr-device-86e4c21e2d4dc300/67d2554/src/interrupt.rs:17:9
   |
17 |           asm!(
   |           ^---
   |           |
   |  _________help: replace with: `llvm_asm!`
   | |
18 | |             "cli" :::: "volatile"
19 | |         );
   | |__________^
   |
   = note: consider migrating to the new asm! syntax specified in RFC 2873
   = note: alternatively, switch to llvm_asm! to keep your code working as it is

error: the legacy LLVM-style asm! syntax is no longer supported
  --> /home/jdrouet/.cargo/git/checkouts/avr-device-86e4c21e2d4dc300/67d2554/src/interrupt.rs:31:9
   |
31 |           asm!(
   |           ^---
   |           |
   |  _________help: replace with: `llvm_asm!`
   | |
32 | |             "sei" :::: "volatile"
33 | |         );
   | |__________^
   |
   = note: consider migrating to the new asm! syntax specified in RFC 2873
   = note: alternatively, switch to llvm_asm! to keep your code working as it is

error: the legacy LLVM-style asm! syntax is no longer supported
  --> /home/jdrouet/.cargo/git/checkouts/avr-device-86e4c21e2d4dc300/67d2554/src/interrupt.rs:48:9
   |
48 |           asm!(
   |           ^---
   |           |
   |  _________help: replace with: `llvm_asm!`
   | |
49 | |             "in $0,0x35"
50 | |             : "=r"(sreg)
51 | |             :
52 | |             :
53 | |             : "volatile"
54 | |         );
   | |__________^
   |
   = note: consider migrating to the new asm! syntax specified in RFC 2873
   = note: alternatively, switch to llvm_asm! to keep your code working as it is

error: aborting due to 3 previous errors

error: could not compile `avr-device`

Do you have any idea on how I could fix that?

Runtime?

All of the chip implementations in the official Rust Embedded project are split into two packages: low level registry access and run-time.

Does that (or will it) map onto the two packages here (avr-device and avr-hal)? Does (or will) avr-hal provide a run-time?

Assembly errors, "invalid instruction mnemonic"

This seems to be related to #29, but happens on linux, even after replacing all symlinks

Steps the reproduce:

sudo docker run -it debian:buster-slim
cd
apt update && apt install -y curl git gcc-avr build-essential
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh  # select nightly 
. /root/.profile
git clone https://github.com/Rahix/avr-hal.git
cd avr-hal
cargo build --examples

This leads to the following error:

root@f54a89809b4a:/avr-hal# cargo build --examples
   Compiling proc-macro2 v1.0.19
   Compiling syn v1.0.38
   Compiling proc-macro-hack v0.5.18
   Compiling nb v0.1.3
   Compiling rustc_version v0.2.3
   Compiling embedded-hal v0.2.4
   Compiling bare-metal v0.2.5
   Compiling quote v1.0.7
   Compiling paste-impl v0.1.18
   Compiling paste v0.1.18
   Compiling avr-device-macros v0.2.0
   Compiling ufmt-macros v0.1.1 (https://github.com/Rahix/ufmt.git?rev=12225dc1678e42fecb0e8635bf80f501e24817d9#12225dc1)
   Compiling avr-device v0.2.1
   Compiling ufmt v0.1.0 (https://github.com/Rahix/ufmt.git?rev=12225dc1678e42fecb0e8635bf80f501e24817d9#12225dc1)
   Compiling avr-hal-generic v0.1.0 (/avr-hal/avr-hal-generic)
   Compiling atmega32u4-hal v0.1.0 (/avr-hal/chips/atmega32u4-hal)
   Compiling atmega328p-hal v0.1.0 (/avr-hal/chips/atmega328p-hal)
   Compiling atmega2560-hal v0.1.0 (/avr-hal/chips/atmega2560-hal)
   Compiling atmega1280-hal v0.1.0 (/avr-hal/chips/atmega1280-hal)
   Compiling attiny85-hal v0.1.0 (/avr-hal/chips/attiny85-hal)
   Compiling arduino-uno v0.1.0 (/avr-hal/boards/arduino-uno)
   Compiling arduino-leonardo v0.1.0 (/avr-hal/boards/arduino-leonardo)
   Compiling trinket v0.1.0 (/avr-hal/boards/trinket)
error: unknown use of instruction mnemonic without a size suffix
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     in %al,0x3F
  |     ^

error: invalid instruction mnemonic 'sei'
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     sei
  |     ^^^

error: aborting due to 2 previous errors

error: could not compile `arduino-uno`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: unknown use of instruction mnemonic without a size suffix
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     in %al,0x3F
  |     ^

error: invalid instruction mnemonic 'sei'
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     sei
  |     ^^^

error: aborting due to 2 previous errors

error: build failed

Thanks a lot for your time and efforts, it's more than awesome to switch away from the arduino ide to rust!

ATMega328p Support

I would like to add support for the ATMega328p to this crate so that I can utilize embedded-hal drivers on my Arduino Uno. Being super new to embedded development, I'd really appreciate a high-level description of what that would take. I'm going to fork this repo and inspect the other boards to figure out how, but a little direction could speed things up a lot. Thanks!

Flashing blink on windows fails because firmware size is too large

Hi,
I initialized a new project for the Arduino Nano board following the startup guide but for the blink example I get a firmware of more than 32kb once compiled.
In the README I understood that the Arduino Nano / UNO were supported but as their flash memory is 32kb I have to do something backwards.

I use this command (under windows) to upload the firmware on the board : avrdude -patmega328p -carduino -PCOM3 -b57600 -D -Uflash:w:avr-example.elf

Here are my source files :

main.rs

#![no_std]
#![no_main]

extern crate panic_halt;

use arduino_uno::prelude::*;

#[arduino_uno::entry]
fn main() -> ! {
    let dp = arduino_uno::Peripherals::take().unwrap();
    let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD);
    let mut led = pins.d13.into_output(&mut pins.ddr);

    loop {
        led.set_high().void_unwrap();
        arduino_uno::delay_ms(1000);
        led.set_low().void_unwrap();
        arduino_uno::delay_ms(1000);
    }
}

cargo.toml

[package]
name = "avr-example"
version = "0.1.0"
authors = ["Nexyll <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
# A panic handler is needed.  This is a crate with the most basic one.
# The `leonardo-panic` example shows a more elaborate version.
panic-halt = "0.2.0"

[dependencies.arduino-uno]
git = "https://github.com/Rahix/avr-hal"
rev = "0c6cf1675c2724354f1adeaeee69992acd371e80"
feature = ["arduino-nano"]

# Configure the build for minimal size
[profile.dev]
panic = "abort"
lto = true
opt-level = "s"

[profile.release]
panic = "abort"
codegen-units = 1
debug = true
lto = true
opt-level = "s"

config.toml

[build]
target = "./avr-atmega328p.json"

[target.'cfg(target_arch = "avr")']
runner = "./uno-runner.sh"

[unstable]
build-std = ["core"]

Revisit board pins reexport macro

The current incarnation of the board pins reexport macro is already quite successfull at abstracting the actual port pins into something that an application developer can comfortably work with.

However, when the need arises to actually name the pin types, it gets awkward: Right now, the are no reexports in place at all so one needs to reference the type from the hal crate and lookup the real port names. As a real-world usecase, consider a global variable holding a pin:

static mut GLOBAL_PIN: Option<atmega32u4_hal::port::portc::PC7> = None;

Of course, it would be much nicer if the actual pin name, as found in the generated Pins struct could be used:

static mut GLOBAL_PIN: Option<arduino_leonardo::pins::D13> = None;

I think it shouldn't be too difficult to add this: The macro needs to emit type aliases for each pin and reference those instead of the port pin types. For this, it needs to grow more syntax to specify the new pin type identifiers. A rough sketch:

// The macro will change from (L692)
pub $name:ident: $pinport:ident::$pin:ident::$Pin:ident,
// to e.g.
pub $name:ident: $Name:ident = $pinport:ident::$pin:ident::$Pin:ident,

// so call-sites will change from
pub d0: portd::pd2::PD2,
// to
pub d0: D0 = portd::pd2::PD2,

// the macro then generates type aliases like
$(
    $(#[$pin_attr])*
    pub type $Name<MODE>: $pinport::$Pin<MODE>;
)+
// and uses them in the struct (L714)
$(
    $(#[$pin_attr])*
    pub $name: $Name<$crate::port::mode::Input<$crate::port::mode::Floating>>,
)+

Delay Accuracy

Delays have bad accuracy for values over 4095ยตs. This is caused by the for loop in the implementation whose overhead is not subtracted:

// TODO: Somehow fix the overhead induced by this loop
for _ in 0..(us >> 12) {
delay::DelayUs::<u16>::delay_us(self, 0xfff);
}

SPI: CS must be configured before SPI peripheral

I'm trying to use the SPI library but it's not working as expected. The send method works fine and returns without incident, but the read method blocks forever.

    let byte = block!(spi.send(5u8).and_then(|_| spi.read()));
    if let Ok(byte) = byte {
        ufmt::uwriteln!(&mut serial, "wrote read {}\r", byte).unwrap();
    } else {
        ufmt::uwriteln!(&mut serial, "not wrote read\r").unwrap();
    }

It never makes it past the block macro, it seems that it's returning WouldBlock forever. All read does is try to flush, code here:

https://github.com/Rahix/avr-hal/blob/master/avr-hal-generic/src/spi.rs#L125

The is_write_in_progress is obviously true as expected, since a send was just executed. But it seems that the write complete status register is not being set.

https://github.com/Rahix/avr-hal/blob/master/avr-hal-generic/src/spi.rs#L127

Documentation for the SPI interrupt flag is in section 18.5.2 of this document:

http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

I'm trying to debug this but any suggestions are welcome.

Windows build fails because of symlinked target files

Heya,

just checked this out on Windows 10 with rust 1.47.0-nightly and tried to run the uno-blink example but got:

$ cargo build --example uno-blink
   Compiling arduino-uno v0.1.0 (C:\Users\grego\code\avr-hal\boards\arduino-uno)
error: unknown use of instruction mnemonic without a size suffix
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     in %al,0x35
  |     ^

error: invalid instruction mnemonic 'sei'
  |
note: instantiated into assembly here
 --> <inline asm>:1:2
  |
1 |     sei
  |     ^^^

error: aborting due to 2 previous errors

error: could not compile `arduino-uno`.

Same problem in WSL 2 Ubuntu with the same rust version. Any pointers would be appreciated, maybe it's something I could look at myself.

Unsafe macros break build

Looks like the commit that went in yesterday (0aef1a6) fixed one layer of the issue, but there seem to be remaining issues. Here's what I got when trying to build today:

error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
  --> /home/jonah/Projects/avr-hal/chips/atmega328p-hal/src/spi.rs:31:1
   |
31 | / avr_hal::impl_spi! {
32 | |     pub struct Spi {
33 | |         peripheral: crate::atmega328p::SPI,
34 | |         pins: {
...  |
39 | |     }
40 | | }
   | |_^ call to unsafe function
   |
   = note: consult the function's documentation for information on how to avoid undefined behavior
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

Tests fail

PART 1

Top level cargo test fails

HASH

commit ad6fedd35a9a17639edf44a59fab6a14b2707cce (HEAD -> master, origin/master, origin/HEAD)
Author: Rahix <[email protected]>
Date:   Mon Sep 7 23:06:02 2020 +0200

    generic: delay: Fix a compiler warning
    
    Remove unnecessary parentheses.
    
    Signed-off-by: Rahix <[email protected]>

REPRO

git clone https://github.com/Rahix/avr-hal
cd avr-hal
rustup override set nightly
cargo build
cargo test

ERROR

   Compiling arduino-uno v0.1.0 (/home/todd/temp/foo/avr-hal/boards/arduino-uno)
   Compiling arduino-mega2560 v0.1.0 (/home/todd/temp/foo/avr-hal/boards/arduino-mega2560)
   Compiling sparkfun-pro-micro v0.1.0 (/home/todd/temp/foo/avr-hal/boards/sparkfun-pro-micro)
   Compiling arduino-leonardo v0.1.0 (/home/todd/temp/foo/avr-hal/boards/arduino-leonardo)
error: Ensure that you are using an AVR target! You may need to change directories or pass a --target flag to cargo. See
       https://github.com/Rahix/avr-device/pull/41 for more details.
  --> boards/arduino-uno/examples/uno-panic.rs:27:1
   |
27 | #[arduino_uno::entry]
   | ^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

EXPECTED

I suspect this is an issue with the use of workspaces. As shown in PART 2 below, running cargo test within one of the crates fails for a different reason there.

Full file attached.
cargo-test-out.txt

QUESTION

Why aren't the tests being run as part of the travis build? I only see cargo build being run.

PART 2

Device cargo test fails, too, but with different errors.

REPRO

cd boards/arduino-uno
cargo build (succeeds)
cargo clean
cargo test

ERROR

   Compiling nb v1.0.0
   Compiling void v1.0.2
   Compiling ufmt-write v0.1.0 (https://github.com/Rahix/ufmt.git?rev=12225dc1678e42fecb0e8635bf80f501e24817d9#12225dc1)
   Compiling cfg-if v0.1.10
   Compiling vcell v0.1.2
   Compiling panic-halt v0.2.0
   Compiling bare-metal v0.2.5
error: duplicate lang item in crate `core` (which `rustc_std_workspace_core` depends on): `bool`.
  |
  = note: the lang item is first defined in crate `core` (which `vcell` depends on)
  = note: first definition in `core` loaded from /home/todd/temp/foo/avr-hal/target/avr-atmega328p/debug/deps/libcore-77c7fc359a8bad07.rmeta
  = note: second definition in `core` loaded from /home/todd/temp/foo/avr-hal/target/avr-atmega328p/debug/deps/libcore-6d69c1e64d8513e0.rmeta
...

EXPECTED

Why don't the tests pass? Why is there this issue with duplicate definitions? Is this the real problem or is this masking some other, known, issue?

ADC cannot read from a Pin<Analog> object.

Hello, this is a great project. When trying to perform the Adc.read method on a Pin<Analog> object, I receive the following error:

the trait bound `arduino_uno::atmega328p_hal::port::Pin<arduino_uno::atmega328p_hal::port::mode::Analog>: embedded_hal::adc::Channel<arduino_uno::adc::Adc>` is not satisfied
required because of the requirements on the impl of `arduino_uno::prelude::_embedded_hal_adc_OneShot<arduino_uno::adc::Adc, _, arduino_uno::atmega328p_hal::port::Pin<arduino_uno::atmega328p_hal::port::mode::Analog>>` for `arduino_uno::adc::Adc` rustc(E0277)

which cleaned up for you benefit becomes:

the trait bound `Pin<Analog>: Channel<Adc>` is not satisfied
required because of the requirements on the impl of `OneShot<Adc, _, Pin<Analog>>` for `Adc` rustc(E0277)

I believe that this just means that the downgraded/generic Pin<Analog> object needs this OneShot trait implemented? It's a little hard to figure out what is and isn't implemented with all of the procedural macros.


Here is a minimal reproducible example:

#![no_std]
#![no_main]
extern crate panic_halt;
use arduino_uno::prelude::*;
use nb;

#[arduino_uno::entry]
fn main() -> ! {
    let peripherals = arduino_uno::Peripherals::take().unwrap();
    let mut pins = arduino_uno::Pins::new(
        peripherals.PORTB, peripherals.PORTC, peripherals.PORTD
    );

    let mut adc = arduino_uno::adc::Adc::new(
        peripherals.ADC, arduino_uno::adc::AdcSettings::default()
    );
    let analog_pin = pins.a0.into_analog_input(&mut adc).downgrade();
    let val: u16 = nb::block!(adc.read(&mut analog_pin)).void_unwrap();
    loop {}
}

macro impl_spi! creates name collision in atmega328pb

the macro impl_spi! creates a struct ChipSelectPin

pub struct ChipSelectPin($csmod::$CS<$crate::port::mode::Output>);

this makes it impossible to declare two spi ports in the same module like atmega328pb does:

avr_hal_generic::impl_spi! {
pub struct Spi0 {
peripheral: crate::pac::SPI0,
pins: {
sclk: portb::PB5,
mosi: portb::PB3,
miso: portb::PB4,
cs: portb::PB2,
}
}
}
avr_hal_generic::impl_spi! {
pub struct Spi1 {
peripheral: crate::pac::SPI1,
pins: {
sclk: portc::PC1,
mosi: porte::PE3,
miso: portc::PC0,
cs: portc::PE2,
}
}
}

currently atmega328pb build is broken.

Consider merging (some) HAL crates

From my perspective as the maintainer of avr-hal, the HAL crates are becoming more and more of a burden to maintain because any global change needs to be reflected in each one. There is a huge amount of code-duplication across the HAL crates which is not helping with this.

I think it makes sense to look into merging at least some of the HAL crates, for chips where the differences are small enough that #[cfg()]s can be used to differentiate between them.

The big question is where to draw the lines, what MCUs should go into which HAL crate:

  • The nuclear solution would be to put all devices of ATmega/ATtiny into a crate. This would leave us with the minimum number of crates but a mess of #[cfg()]s to manage them.
  • On the other end of the spectrum, we could just go by the families as described by Microchip in their Overview (PDF). For the current set of supported MCUs this would not give us much advantage over the current situation, though.

IMO we need to larger grouping than the "Microchip Families" but just forcing all ATmega/ATtiny devices into a single crate also looks scary. The latter might still be manageable now, but looking into the future, with more and more devices being supported, I can see it becoming a large mess.

Not yet sure what to do ...

Proposals

"Nuclear" Split, atmega/atxmega/attiny

The nuclear solution would be to put all devices of ATmega/ATtiny into a crate. This would leave us with the minimum number of crates but a mess of #[cfg()]s to manage them.

Pros

  • Least amount of crates
  • (Probably) least amount of code duplication

Cons

  • Many #[cfg()]s to differentiate

Split by Architecture

Group devices by the instruction set they use.

Pros

  • Well defined separation.

Cons

  • There are similarities cross-architecture which means we'd still have a lot of duplicated code.

Split by Generation/Series

Original Comment:

The last digit marks the series of chips. We can group them like this (for example):

  • no digit
  • 8, 4, 5
  • 0, 1
  • U*

Pros

  • Devices in each series/generation are very similar so it is mostly about presence vs non-presence of a certain peripheral.
  • This also means not many special cases to consider.

Cons

  • Still ends up with a lot of crates (at least 4 for atmega, atxmega and attiny unclear)
  • Blurry lines where generations end/where to split. Only 0-series is a well defined difference.

Split by Family

On the other end of the spectrum, we could just go by the families as described by Microchip in their Overview (PDF). For the current set of supported MCUs this would not give us much advantage over the current situation, though.

Pros

  • Well defined separation.

Cons

  • Lots of crates, pretty much where we're at right now.

How to get a pin's mask or pin number

I cannot seem to figure out how can I retrieve the pin number programmatically.
My intention is do be able to write something similar to what you do in /avr-generic/port.rs does but in my main code base:

unsafe {
    (*<$PORTX>::ptr()).$reg_port.modify(|r, w| {
        w.bits(r.bits() & !(1 << $i))
    });
}

For which I need $i.
But I am not able to find an way on how to obtain that number. Could you provide an example on how to achieve this?

Investigate how to add reconfiguration to generic pins

Right now, after calling .downgrade() to cast a pin into the generic type, there is no possibility to change its mode anymore. It would be nice if the .into_*() methods would also exist for generic pins.

The biggest issue in implementing this is how to pass the DDR register to the methods in a way that allows a runtime check whether the right DDR was passed. As a start, I would suggest this pattern:

pub enum GenericDDR {
    PORTA(DDRA),
    PORTB(DDRB),
}

// ...
pub fn into_output(self, ddr: impl AsRef<GenericDDR>) -> ... {
    if let GenericDDR::PORTA(ddra) = ddr {
        ...
    } else { panic!() }
}

// and
impl AsRef<GenericDDR> for DDRA {
    ...
}

More efficient pin toggling

Right now, pin-toggling is implemented naively using the default embedded-hal implementation:

impl digital::toggleable::Default for $GenericPin<mode::Output> {}

This will essentially boil down to reading the current state, inverting it, and writing that back. We can do better! It turns out, by writing a 1 to the PINn register, the MCU will take care of toggling PORTn. With the next version of avr-device, commit 7c3805f9d84d ("Make the PINx registers writeable") which was introduced by @couchand in PR Rahix/avr-device#45, this will actually be possible to implement here.

Set up CI for avr-hal

Now that nightly can compile for AVR, it would make sense to set up CI here as well.

error: Could not create LLVM TargetMachine for triple: avr-unknown-unknown: No available targets are compatible with triple "avr-unknown-unknown"

Hi,
I am working from the avr-hal basic template project.

When I try to refresh the cargo project(I am on intelliJ ultimate) project I get error:

10:24 Cargo project update failed:
Execution failed (exit code 101).
/Users/aissata/.cargo/bin/cargo metadata --verbose --format-version 1 --all-features
stdout : error: failed to run rustc to learn about target-specific information

		Caused by:
		  process didn't exit successfully: `rustc - --crate-name ___ --print=file-names --target /Users/aissata/Rust/avr-example/avr-atmega328p.json --crate-type bin --crate-type rlib --crate-type dylib --crate-type cdylib --crate-type staticlib --crate-type proc-macro --print=sysroot --print=cfg` (exit code: 1)
		--- stderr

error: Could not create LLVM TargetMachine for triple: avr-unknown-unknown: No available targets are compatible with triple "avr-unknown-unknown"

Add ability to re-configure SPI.

I'm trying to use SPI to read off an SD card, and part of the requirements of an SD card is that it needs to initialize at 100-400kHz, but then you can run it faster afterwards.

I'm using embedded-sdmmc, and it allows you to reconfigure the peripheral after initializing through a function. However as this HAL currently exists, there is no way to do that other than releasing the existing instance and creating a new one.

I have tested the following and it seems to work (haven't built the hardware to test yet):

impl $Spi {
    [...]
    /// Reconfigure SPI peripheral without releasing pins.
    pub fn reconfigure(&mut self, settings: Settings) {
        self.settings = settings;
        self.setup();
    }
    [...]
}

Create a project template

Similar to cortex-m-quickstart, we should provide a cargo-generate template for AVR. I'm not sure how exactly to design that to make it easy to start with any device from the same template but I'm sure there is a way to make this work. Otherwise, several templates for different popular boards could also work.

Serial port setup: baud_rate/8/N/1 doesn't work when uploading examples to Arduino Uno rev2

I'm getting gibberish on serial port.
I've uploaded examples to my Arduino Uno rev2 board via cargo +nightly run --example uno-serial and cargo +nightly run --example uno-adc. I've played with several baud_rates (switched uno-serial.rs example from 57600 to 9600). I cannot get the correct setup to retrieve the data. The upload process is correct and other examples (uno-blink.rs) are working correctly.

Also, code from Arduino IDE behaves correctly in terms of Serial port communication.

Open drain behaviour simulation

Hello.

As I can see it is not possible to have Pin that implements InputPin + OutputPin trait at the same time.
This happens because pin it consumes itself while mode change. Thus implement open/drain behavior is extremely hard in 3rd party code.

But the thing is that Arduino have modules that communicates via single wire with pull up resistor in both direction (send/receive data). From Arduino libraries you can see that they try to emulate open drain behavior by switching pin to input mode when it is needed to set pin high or read state, and only to set pin low it is switched into output mode.

It would be really nice to have such behavior here with InputPin + OutputPin traits implementation at the same time.

More fine grained control of serial baudrate

Currently, the code only allows specifying a baudrate which the HAL-driver will try to match as closely as possible. The "generic" algorithm used for this will not always produce the most optimal settings, however. This means, for example, that 115200 baud on Arduino Uno is completely broken.

It would be nice to also allow setting exact baudrate parameters or/and providing alternate algorithms. There are quite a few ways to implement this, here are a few ideas:

  1. A new Baudrate type with methods for the different modes:

    // Clock is needed because the calculations needs to take core clock into account
    pub struct Baudrate<CLOCK> {
        pub ubrr: u16,
        pub u2x: bool,
        pub _clock: PhantomData<CLOCK>,
    }
    
    impl<CLOCK: crate::clock::Clock> Baudrate<CLOCK> {
        pub fn new(baud: u32) -> Baudrate<CLOCK> {
            // current implementation
        }
    
        pub fn with_exact(u2x: bool, ubrr: u16) -> Baudrate<CLOCK> {
            Baudrate { ubrr, u2x, _clock: PhantomData }
        }
    }

    The Usart constructor now takes Baudrate<CLOCK> instead of u32.

  2. Using an Into<Baudrate<CLOCK>> bound in the Usart constructor. We also implement From<u32> for Baudrate<CLOCK>. This would allow backwards compatibility with current code (but I'm not sure if that is a good thing ...).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.