ok great, thank you for your response. That works as you proposed.
I finally got Firmata running on the ATtiny841.
I am able to control the chip using Scratch over Bluetooth.
I am using it to run two motors through a Dual Motor Driver.
I am now very knowledgeable about all the ways you can go wrong trying to do this.
I have DrAzzy's board. I'm using his core and Arduino 1.6.5. I programmed the board using both a USBasp programmer and a Nano. (Programming using the Nano works but it is too slow)
(I can't be the only one who was careless and bricked the board by burning a bootloader/ setting fuses for an external crystal by mistake. Luckily there is an easy fix using an Arduino.
Attach the Arduino clock pin (Pin 9) to the XTAL1 pin (DrAzzy Pin 0) on the ATtiny841)
The issue about master/slave I2C I asked about earlier in this thread turned out to be a red herring. I only needed the ATtiny841 hardware serial pins to communicate through the Bluetooth HC05.
(i) I didn't need to but the HC05 also lets you implement auto-resetting the Arduino upon serial connection easily enough.
(Connect pin 32 on the HC05 to RST on the ATtiny841. )
(ii) There is an issue with serial connection to the HC05 if you have version 1.6 of the JY-MCU Bluetoooth module.
( TX Pin of the chip on the HC05 board needs to be connected directly to the AtTiny841 RX pin. )
I added the following to Boards.h
// ATtiny841
#elif defined(__AVR_ATtiny841__)
#define TOTAL_ANALOG_PINS 12
#define TOTAL_PINS 12
#define VERSION_BLINK_PIN 2
#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <=7) || (p) == 10 || (p) == 11)
#define IS_PIN_ANALOG(p) (((p) >= 0 && (p) <=7) || (p) == 10 || (p) == 11)
#define IS_PIN_PWM(p) ((p) >= 2 && (p) <=7)
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
#define IS_PIN_I2C(p) ((p) == 4 || (p) == 6)
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
#define PIN_TO_DIGITAL(p) (p)
#define PIN_TO_ANALOG(p) (p)
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
#define PIN_TO_SERVO(p) (p)
When it came to Firmata itself there were a few problems.
Apart from issues concerning the Wire library any recent Firmata was just too big for the ATtiny841. Once I realised I only needed the hardware serial connection I went back to the earliest 'modern' version of StandardFirmata, version 2.2, which only used serial to communicate. (It was still too big but I ;
(i) removed all references to servos
(ii) removed the Firmata.sendString error messages
(iii) replaced Firmata.setFirmwareVersion(2, 2);
with Firmata.setFirmwareNameAndVersion("name", 2, 2);
I don't know why (ii) was necessary.
I think (iii) was needed because of a particularly messy directory structure in my Arduino setup.
I attached the HC05 to the ATtiny841 as usual; VCC-VCC GND-GND TX-RX RX-TX
I used Matthew Preece's A4S server here.
I made a few custom blocks for Scratch.
I used the little TB6612FNG Dual Motor Driver. Its APwm, A1in, A2in, BPwm, B1in and B2in pins can be attached to any pemutation of pins 2 to 7 on the ATtiny841
(I was also successfull with a L298N )
I could then run the motors from Scratch.
So only one question remains. Why do all this? (I had already done all the above, with much less effort, for a Nano in place of the ATtiny841.)
Answer, because of this.
Codefox has put an ATtiny841, a HC05 and a motor driver together on one small board and designed a 4x3 Lego brick to contain them.
He is charging less than €30 for the lot. Load up Firmata, throw in a couple of motors, some Lego electrical connectors, a battery box and the ability to program over Bluetooth using Scratch and you have Mindstorms for under €40.
If anyone wants more detail on any of what I did please ask.
There are probably smarter ways to cut down StandardFirmata.ino, it may even be possible to save the servos, and I'd be delighted to hear about them.
Thanks for everyone's help especially DrAzzy.
StandardFirmata22lessServos.ino (14 KB)
Cool!
You should put that into a github repo - that's how all the cool kids are distributing code.
Do that and I'll link to it from my repo.
Feel free to stick it up on your own repo DrAzzy. I'm not looking for credit. It would be great if you could have a look at the three problems with the .ino mentioned above.
Restoring the servos
Letting Firmata send error messages
Going with the default setFirmwareVersion command
You may not even have a problem with the last one
Hi there,
I have a problem with the PinChange Interrupt: when I set PCIE0 in the GIMSK register to activate the PCint7:0 I can't use the OCR1B any longer. I use the OCR1A, OCR2A and OCR2B for driving servos (runs very nice). But only OCR1B (routed to TOCC4) is not working.
Any Ideas ?
Marco
marcedi:
Hi there,I have a problem with the PinChange Interrupt: when I set PCIE0 in the GIMSK register to activate the PCint7:0 I can't use the OCR1B any longer. I use the OCR1A, OCR2A and OCR2B for driving servos (runs very nice). But only OCR1B (routed to TOCC4) is not working.
Any Ideas ?
Marco
what does "I can't use" and "not working" mean?!
When you report a problem, you need to describe the symptoms? Does it not output anything? output wrong signal? What signal, if so? Or does it crash the chip? Or does it open a rift to hell and summon the undead? Give me something to work with here, man!
Could you have enabled the PCINT on that pin in PCMSK?
DrAzzy:
Or does it open a rift to hell and summon the undead?
Tiny841 can do that !!! Datasheet do not mention that option.
Sorry for my bad Post !
I tested this morning with to following code:
#define RUDDER_PIN 6
#define MOTORL_PIN 5
#define MOTORR_PIN 3
#define QSR_PIN 4
#define RC_RUDDER_PIN 10
#define RC_MOTOR_PIN 9
#define RC_QSR_PIN 8
#define RC_SWITCH_PIN 7
// -----------------------------
// variables
// -----------------------------
uint8_t i = 0;
uint8_t pin_array[8] { RUDDER_PIN, MOTORL_PIN, MOTORR_PIN, QSR_PIN, RC_RUDDER_PIN, RC_MOTOR_PIN, RC_QSR_PIN, RC_SWITCH_PIN };
...
// -----------------------------
// Setup
// -----------------------------
void setup() {
for(i = 0; i < 4; i++) {
pinMode(pin_array[i], OUTPUT);
digitalWrite(pin_array[i], LOW);
}
for(i = 4; i < 8; i++) {
pinMode(pin_array[i], INPUT);
}
start_servos();
delay(500);
start_rc_input();
}
// -----------------------------
// Main loop
// -----------------------------
void loop() {
OCR1B=1000;
OCR1A=1000;
OCR2A=1000;
delay(500);
OCR1B=2000;
OCR1A=2000;
OCR2A=2000;
delay(500);
}
// -----------------------------
// Subroutine: Start Servo Output
// -----------------------------
void start_servos() {
//Timer 1
ICR1 = 20000;
TCCR1A = 0;
bitSet(TCCR1A,COM1A1);
bitSet(TCCR1A,COM1B1);
bitSet(TCCR1A,WGM11);
TCCR1B = 0;
bitSet(TCCR1B,WGM12);
bitSet(TCCR1B,WGM13);
bitSet(TCCR1B,CS11);
TOCPMSA0 = 0;
TOCPMSA1 = 0;
TOCPMCOE = 0;
bitSet(TOCPMSA0, TOCC3S0); // route OCR1A Output to TOCC3
bitSet(TOCPMCOE, TOCC3OE);
bitSet(TOCPMSA1, TOCC4S0); // route OCR1B Output to TOCC4
bitSet(TOCPMCOE, TOCC4OE);
TCNT1 = 0;
OCR1A = 1500;
OCR1B = 1500;
//Timer 2
ICR2 = 20000;
TCCR2A = 0;
bitSet(TCCR2A,COM2A1);
bitSet(TCCR2A,COM2B1);
bitSet(TCCR2A,WGM11);
TCCR2B = 0;
bitSet(TCCR2B,WGM12);
bitSet(TCCR2B,WGM13);
bitSet(TCCR2B,CS11);
bitSet(TOCPMSA1, TOCC5S1); // route OCR2A Output to TOCC5
bitSet(TOCPMCOE, TOCC5OE);
TCNT2 = 0;
OCR2A = 1500;
}
// -----------------------------
// Subroutine: Start RC Input
// -----------------------------
void start_rc_input() {
bitSet(GIMSK, PCIE0);
bitSet(PCMSK0, PCINT0);
bitSet(PCMSK0, PCINT1);
bitSet(PCMSK0, PCINT2);
}
// -----------------------------
// Interrupt for RC Input
// -----------------------------
ISR (PCINT0_vect) {
// Rudder RC Input
if(digitalRead(RC_RUDDER_PIN)) {
start_micros_rudder = micros();
rudder_measurement = true;
}
if(!digitalRead(RC_RUDDER_PIN) && rudder_measurement) {
stop_micros_rudder = micros();
rudder_measurement = false;
rudder_measurement_new = true;
}
// Motor RC Input
if(digitalRead(RC_MOTOR_PIN)) {
start_micros_motor = micros();
motor_measurement = true;
}
if(!digitalRead(RC_MOTOR_PIN) && motor_measurement) {
stop_micros_motor = micros();
motor_measurement = false;
motor_measurement_new = true;
}
// QSR RC Input
if(digitalRead(RC_QSR_PIN)) {
start_micros_qsr = micros();
qsr_measurement = true;
}
if(!digitalRead(RC_QSR_PIN) && qsr_measurement) {
stop_micros_qsr = micros();
qsr_measurement = false;
qsr_measurement_new = true;
}
}
This works. But when I insert PCInterrupt for PCINT3 in the "start_rc_input" subroutine
bitSet(PCMSK0, PCINT3);
and insert this to the ISR
// Switch RC Input
if(digitalRead(RC_SWITCH_PIN)) {
start_micros_switch = micros();
switch_measurement = true;
}
if(!digitalRead(RC_SWITCH_PIN) && switch_measurement) {
stop_micros_switch = micros();
switch_measurement = false;
switch_measurement_new = true;
}
the servo on TOCC4 (D5) won't work.
Hope this is more clear.
Marco
The heck? You're clearing out all the relevant registers, as far as I can tell, so there shouldn't be any PWM on that pin or anything....
I've got nothing. I assume the contents of the ISR has no effect? I mean, I can't see why it would, but I can't see why that doesn't work either. (note: I have not attempted to reproduce - if you have a scope, check what it's outputting on that pin, if anything)
common_ground:
Tiny841 can do that !!! Datasheet do not mention that option.
Oh, yeah, just set the the 16-bit DPDR (Dimensional Portal Destination Register - note the section on writing to 16-bit registers; very important here) to 0x666....
Quick question, if anybody can help me.
I've got the 841 working quite happily, utilising i2c. It runs really well. However, I'd like to know if it's possible to change i2c speed to 400 kHz, and also if it is possible to deactivate the internal pull ups. I see how it's done for the Arduinos, but can't see how I can achieve this on the 841. I'm using the WireS library, which works very well overall
Can anybody push me in the right direction?
Cheers,
Dan
I have been wondering about a smaller footprint device to use instead of a DIP Atmega 328 and I may be able to manage an SOIC chip. My search has led me to the 841 (and the 1634) and to this Thread.
What do I need to do to be able to use one of your cores?
...R
PS, I did not originally realize there are 12 pages in this Thread but I have now skimmed through them without spotting instructions for addding the core.
Robin2:
I have been wondering about a smaller footprint device to use instead of a DIP Atmega 328 and I may be able to manage an SOIC chip. My search has led me to the 841 (and the 1634) and to this Thread.What do I need to do to be able to use one of your cores?
...R
PS, I did not originally realize there are 12 pages in this Thread but I have now skimmed through them without spotting instructions for addding the core.
Install instructions here. It can now be installed via board manager - most of this thread is old, and predates that, and the merge of the two cores.
Sorry for the trouble. I had found the instructions just as you replied - I was intending to delete Reply #170
Many thanks.
Now the only "problem" is to figure if I can do what I want in the limited SRAM
...R
Hallo,
I have an nacked ATTiny841 flashed. After correct the Fuse Bit CKDIV8, is correct the blink frequency.
But, the IDE show many warnings.
IDE 1.6.9.
841 Core over Board Manager installed.
void setup()
{
pinMode(3, OUTPUT);
}
void loop()
{
digitalWrite(3, HIGH);
delay(1000);
digitalWrite(3, LOW);
delay(1000);
}
\pins_arduino.c:213:3: warning: initialization makes integer from pointer without a cast [enabled by default]
&PCMSK0,
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.c:213:3: warning: (near initialization for 'port_to_pcmask_PGM[1]') [enabled by default]
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.c:214:3: warning: initialization makes integer from pointer without a cast [enabled by default]
&PCMSK1,
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.c:214:3: warning: (near initialization for 'port_to_pcmask_PGM[2]') [enabled by default]
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_analog.c: In function 'analogRead':
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_analog.c:50:5: warning: comparison is always true due to limited range of data type [-Wtype-limits]
if ( pin >= CORE_ANALOG_FIRST ) pin -= CORE_ANALOG_FIRST; // allow for channel or pin numbers
^
In file included from C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:30:0:
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c: In function 'pinMode':
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:76:31: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_mode_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:45:9: note: in expansion of macro 'portModeRegister'
reg = portModeRegister(port);
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:74:33: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:46:9: note: in expansion of macro 'portOutputRegister'out = portOutputRegister(port);
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:141:33: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portPullupRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_pullup_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:47:9: note: in expansion of macro 'portPullupRegister'
pue = portPullupRegister(port);
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c: In function 'digitalWrite':
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:74:33: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:186:9: note: in expansion of macro 'portOutputRegister'
out = portOutputRegister(port);
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:141:33: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portPullupRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_pullup_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:187:9: note: in expansion of macro 'portPullupRegister'
pue = portPullupRegister(port);
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c: In function 'digitalRead':
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:75:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_digital.c:244:7: note: in expansion of macro 'portInputRegister'
if (*portInputRegister(port) & bit) return HIGH;
^
In file included from C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_pulse.c:26:0:
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_pulse.c: In function 'pulseIn':
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:75:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_pulse.c:48:11: note: in expansion of macro 'portInputRegister'
while ((*portInputRegister(port) & bit) == stateMask)
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:75:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_pulse.c:53:11: note: in expansion of macro 'portInputRegister'
while ((*portInputRegister(port) & bit) != stateMask)
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:75:32: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\wiring_pulse.c:58:11: note: in expansion of macro 'portInputRegister'
while ((*portInputRegister(port) & bit) == stateMask) {
^
In file included from C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\Tone.cpp:41:0:
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\Tone.cpp: In function 'void tone(uint8_t, unsigned int, long unsigned int)':
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\pins_arduino.h:74:95: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) )
^
C:\Users\Worker\AppData\Local\Arduino15\packages\ATTinyCore\hardware\avr\1.1.1\cores\tinymodern\Tone.cpp:216:33: note: in expansion of macro 'portOutputRegister'
tone_timer_pin_register = portOutputRegister( digitalPinToPort( _pin ) );
^
Der Sketch verwendet 924 Bytes (12%) des Programmspeicherplatzes. Das Maximum sind 7.552 Bytes.
Globale Variablen verwenden 9 Bytes (1%) des dynamischen Speichers, 503 Bytes für lokale Variablen verbleiben. Das Maximum sind 512 Bytes.
Those are warnings, not errors.
They warn that I'm using a byte array to store pointers to the PORTx/PINx/DDRx registers, when pointers are 16-bit. In the general case, this is very dangerous - imagine a 16-bit pointer getting truncated to 8 bits - it now points to something totally different! But in the specific case, we know (from the datasheet) that the addresses of these particular registers are below 0x00FF, so it is safe to store them in a byte array - and doing so shrinks the code size by a little (which is why it's done). I have not been able to find a way to suppress those warnings while showing other warnings - but rest assured that these do not indicate a problem.
Hallo,
the problem is, debugging a program. Important warnings and errors are not easy show of me.
To many warnings overlayed real warnings/errors.
Can you fix your warnings? Please.
Thank you very much for all the useful stuff on your Github page.
I forgot to say this in my earlier Replies .
...R