Bonjour tout le monde !
J'ai un (enfin deux) probléme avec un projet en cours, et j'arrive pas à m'en sortir :~
Je suis en train de faire un systéme à base d'ATtiny85 qui génère deux signaux carré de fréquence défini.
Pour ceux faire j'utilise timer0 et timer1, le schéma de mon montage est en pièce jointe.
Le principe : L'ATtiny attend sur le bus I2C deux octets, un premier qui sert de commande, et un deuxième qui sert de valeur.
En gros les "paquets" I2C on cette forme (syntaxe : bus pirate) :
[ adresseI2C canal fréquence ]
"canal" peut prendre les valeurs 0, 1 ou 2.
0 étant un canal spécial qui permet d'arrêter un timer.
Les fréquences sont codé via une valeur de 0 à 127, qui correspond aux notes de musique que génère miditones à partir d'un fichier midi (Google Code Archive - Long-term storage for Google Code Project Hosting.).
Exemple :
[ 0 1 69 ] -> 440Hz sur ch1
[ 0 2 69 ] -> 440Hz sur ch2
[ 0 0 1 ] -> ch1 silence
[ 0 0 2 ] -> ch2 silence
Sauf que (se serait trop beau si tout marchait du 1er coup)
Dans mon code je défini 0x20 comme adresse d'esclave :
/* I2C Node Address */
#define I2C_NODE_ADDRESS 0x20
Puis j'utilise la librairie usiTwiSlave pour gérer les communications I2C
/* Seting up I2C Slave */
usiTwiSlaveInit(I2C_NODE_ADDRESS);
sei();
Je devrai donc pouvoir communiquer avec mon Attiny sur l'adresse 0x20, sauf que aprés avoir fait un scan rapide avec ma carte bus pirate, il s'avére que mon Attiny répond sans probléme, mais sur l'adresse 0x00 !
Comme je prévoie de faire 8 modules il faut absolument que la gestion des adresses marche :~
Ensuite probléme plus grave, j'utilise les timer 0 & 1 en CTC (clear on timer compare) pour générer les deux signaux.
Sauf que j'ai une énorme différence de fréquence entre timer1 et timer0, pourtant je pense avoir correctement choisi mes prescaller ...
Exemple : [ 0 1 69 ] -> 440Hz sur ch1, en sortie sur mon fréquencemètre : 439Hz (Ok)
[ 0 2 69 ] -> 440Hz sur ch2, en sortie sur mon fréquencemètre : 121.5Hz (!?)
ch1 semble donc fonctionner, mais ch2 pas pas du tout, en faite je crois que mes prescaller pour le timer2 sont complétement faux
Bref ... mon truc marche pas et je vois pas comment m'en sortir =(
Help ... Doit bien y avoir un mordu de datasheet et de registre dans l'assistance
Mon code :
/*
* TinySound - Simple, I2C controled, 2 channel music generator
* Coded by SkyWodd <skyduino.wordpress.com>
*
* Based on arduino-playtune (http://code.google.com/p/arduino-playtune/)
* and miditones (http://code.google.com/p/miditones/)
*/
/*
* ATtiny85 Fuses :
* PLL Clock; Start-up time PWRDWN/RESET: 1K CK/14 CK + 4 ms; [CKSEL=0001 SUT=00]
* Brown-out detection level at VCC=4.3 V; [BODLEVEL=100]
* Preserve EEPROM memory through the Chip Erase cycle; [EESAVE=0]
* Serial program downloading (SPI) enabled; [SPIEN=0]
*/
/* Includes */
#include <avr/interrupt.h> /* For Timer Interrupt */
#include <avr/pgmspace.h> /* For PROGMEM */
#include "usiTwiSlave.h" /* For I2C Slave */
#include <avr/io.h> /* For I/O usage */
/* I2C Node Address */
#define I2C_NODE_ADDRESS 0x20
/* PinMapping Definition */
#define SOUND_OUT_1_BIT 3
#define SOUND_OUT_2_BIT 4
#define WORKING_LED_BIT 1
/* Usage Macro */
#define setLedOn() PORTB |= (1 << WORKING_LED_BIT)
#define setLedOff() PORTB &= ~(1 << WORKING_LED_BIT)
#define setLedToggle() PORTB ^= (1 << WORKING_LED_BIT)
#define setChan1On() TIMSK |= (1 << OCIE0A)
#define setChan1Off() TIMSK &= ~(1 << OCIE0A); PORTB &= ~(1 << SOUND_OUT_1_BIT)
#define setChan2On() TIMSK |= (1 << OCIE1A)
#define setChan2Off() TIMSK &= ~(1 << OCIE1A); PORTB &= ~(1 << SOUND_OUT_2_BIT)
/* Chromatic Frequency Table */
const uint16_t PROGMEM tune_freq[128] =
{
16,17,18,19,21,22,23,24,26,28,29,31,33,35,37,39,41,
44,46,49,52,55,58,62,65,69,73,78,82,87,92,98,104,110,
117,123,131,139,147,156,165,175,185,196,208,220,233,
247,262,277,294,311,330,349,370,392,415,440,466,494,
523,554,587,622,659,698,740,784,831,880,932,988,1047,
1109,1175,1245,1319,1397,1480,1568,1661,1760,1865,1976,
2093,2217,2349,2489,2637,2794,2960,3136,3322,3520,3729,
3951,4186,4435,4699,4978,5274,5588,5920,6272,6645,7040,
7459,7902,8372,8870,9397,9956,10548,11175,11840,12544,
13290,14080,14917,15804,16744,17740,18795,19912,21096,
22351,23680,25088
};
/* Timer0 Interrupt */
ISR(TIMER0_COMPA_vect) {
PORTB ^= 1 << SOUND_OUT_1_BIT;
}
/* Timer1 Interrupt */
ISR(TIMER1_COMPA_vect) {
PORTB ^= 1 << SOUND_OUT_2_BIT;
}
/* Tune Channel to frequency */
void set_channel(uint8_t channel, uint8_t note) {
uint8_t prescalarbits;
uint16_t ocr, freq2 = pgm_read_word(tune_freq + note);
// make sure the note isn't too low to be playable
if (note < 24) return; // ignore if so
ocr = F_CPU / freq2 - 1;
prescalarbits = 0b001; // ck/1
if (ocr > 255) {
ocr = F_CPU / freq2 / 8 - 1;
prescalarbits = (channel == 1) ? 0b010 : 0b100; // ck/8
if (ocr > 255) {
ocr = F_CPU / freq2 / 64 - 1;
prescalarbits = (channel == 1) ? 0b011 : 0b111; // ck/64
if (ocr > 255) {
ocr = F_CPU / freq2 / 256 - 1;
prescalarbits = (channel == 1) ? 0b100 : 0b1001; // ck/256
if (ocr > 255) {
ocr = F_CPU / freq2 / 1024 - 1;
prescalarbits = (channel == 1) ? 0b101 : 0b111; // ck/1024
}
}
}
}
if (channel == 1) {
TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;
OCR0A = ocr & 255;
} else {
TCCR1 = (TCCR1 & 0b11110000) | prescalarbits;
OCR1A = ocr & 255;
}
}
/* Entry Point */
int main(void) {
/* Variables */
uint8_t channel;
uint8_t note;
/* Channels & Led Pin As Output */
DDRB |= (1 << SOUND_OUT_1_BIT) | (1 << SOUND_OUT_2_BIT) | (1 << WORKING_LED_BIT);
/* Seting up Timer To CTC Mode */
/* Timer0 */
TCCR0A = 1 << WGM01;
TCCR0B = 1 << CS00;
/* Timer1 */
TCCR1 = (1 << CS10) | (1 << CTC1);
/* Stop Interrupt */
setChan1Off();
setChan2Off();
setLedOff();
/* Seting up I2C Slave */
usiTwiSlaveInit(I2C_NODE_ADDRESS);
sei();
/* Forever loop */
for(;;) {
/* If Data Sent Over I2C */
if(usiTwiDataInReceiveBuffer()) {
setLedToggle();
channel = usiTwiReceiveByte();
note = usiTwiReceiveByte();
switch(channel) {
case 0:
if(note == 1) {
setChan1Off();
} else if(note == 2) {
setChan2Off();
}
break;
case 1:
set_channel(1, note & 127);
setChan1On();
break;
case 2:
set_channel(2, note & 127);
setChan2On();
break;
}
}
}
}
Mon makefile :
DEVICE=attiny85
AVRDUDE = avrdude -c usbtiny -p $(DEVICE)
COMPILE = avr-gcc -Wall -Os -I. -mmcu=$(DEVICE) -DF_CPU=16000000 -DDEBUG_LEVEL=0
SIZE = avr-size --mcu=$(DEVICE)
OBJECTS = usiTwiSlave.c tinysound.c
all: $(OBJECTS) clean
$(COMPILE) -o main.bin $(OBJECTS)
avr-objcopy -j .text -j .data -O ihex main.bin main.hex
$(SIZE) main.hex
rm -f *.bin
flash:
$(AVRDUDE) -U flash:w:main.hex
fuse:
$(AVRDUDE) -U lfuse:w:0xc1:m -U hfuse:w:0xd4:m -U efuse:w:0xff:m
clean:
rm -f *.o *.bin *.hex