Bonjour à vous, c'est encore moi ^^
J'ai une petite question sur la modification du code d'ELM, pour le controler via I2C, le main qu'il faut compiler est celui ci Ici
lien trouvé dans la section allemande ICI
/* 8-pin SD audio player R0.04 (C)ChaN, 2010 */
/*-------------------------------------------------*/
// modified by using I2C interface, waiting for song number, then
// play selected song
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <string.h>
#include "diskio.h"
#include "pff.h"
#ifndef MODE
#error Wrong make file.
#endif
#define FCC(c1,c2,c3,c4) (((DWORD)c4<<24)+((DWORD)c3<<16)+((WORD)c2<<8)+(BYTE)c1) /* FourCC */
/*---------------------------------------------------------*/
/* Work Area */
/*---------------------------------------------------------*/
volatile BYTE FifoRi, FifoWi, FifoCt; /* FIFO controls */
BYTE Buff[256]; /* Wave output FIFO */
FATFS Fs; /* File system object */
DIR Dir; /* Directory object */
FILINFO Fno; /* File information */
WORD rb; /* Return value. Put this here to avoid bugs of avr-gcc */
EMPTY_INTERRUPT(WDT_vect);
/*---------------------------------------------------------*/
static
DWORD load_header (void) /* 0:Invalid format, 1:I/O error, >1:Number of samples */
{
DWORD sz;
if (pf_read(Buff, 12, &rb)) return 1; /* Load file header (12 bytes) */
if (rb != 12 || LD_DWORD(Buff+8) != FCC('W','A','V','E')) return 0;
for (;;) {
pf_read(Buff, 8, &rb); /* Get Chunk ID and size */
if (rb != 8) return 0;
sz = LD_DWORD(&Buff[4]); /* Chunk size */
switch (LD_DWORD(&Buff[0])) { /* FCC */
case FCC('f','m','t',' ') : /* 'fmt ' chunk */
if (sz > 100 || sz < 16) return 0; /* Check chunk size */
pf_read(Buff, sz, &rb); /* Get content */
if (rb != sz) return 0;
if (Buff[0] != 1) return 0; /* Check coding type (1) */
if (Buff[2] != 1 && Buff[2] != 2) /* Check channels (1/2) */
return 0;
GPIOR0 = Buff[2]; /* Get channel flag */
if (Buff[14] != 8 && Buff[14] != 16) /* Check resolution (8/16) */
return 0;
GPIOR0 |= Buff[14]; /* Resolution flag */
OCR0A = (BYTE)(F_CPU/8/LD_WORD(&Buff[4]))-1; /* Sampling freq */
break;
case FCC('d','a','t','a') : /* 'data' chunk (start to play) */
return sz;
case FCC('L','I','S','T') : /* 'LIST' chunk (skip) */
case FCC('f','a','c','t') : /* 'fact' chunk (skip) */
pf_lseek(Fs.fptr + sz);
break;
default : /* Unknown chunk (error) */
return 0;
}
}
return 0;
}
static
UINT play (
const char *fn
)
{
DWORD sz;
FRESULT res;
BYTE sw;
WORD btr;
if ((res = pf_open(fn)) == FR_OK) {
sz = load_header(); /* Load file header */
if (sz < 256) return (UINT)sz;
if (!TCCR1) { /* Enable audio out if not enabled */
PLLCSR = 0b00000110; /* Select PLL clock for TC1.ck */
GTCCR = 0b01100000; /* Enable TC1.OCB as PWM out (L-ch) */
OCR1B = 128; OCR1A = 128;
TCCR1 = MODE ? 0b01100001 : 0b00000001; /* Start TC1 with TC1.OCA is enabled as PWM out (R-ch) */
TCCR0A = 0b00000010; /* Enable TC0.ck = 2MHz as interval timer */
TCCR0B = 0b00000010;
TIMSK = _BV(OCIE0A);
}
FifoCt = 0; FifoRi = 0; FifoWi = 0; /* Reset FIFO */
pf_read(0, 512 - (Fs.fptr % 512), &rb); /* Snip sector unaligned part */
sz -= rb;
sw = 1; /* Button status flag */
do {
/* Forward audio data */
btr = (sz > 1024) ? 1024 : (WORD)sz;
res = pf_read(0, btr, &rb);
if (res != FR_OK || btr != rb) break;
sz -= rb;
/* Check button down and break on button down */
sw <<= 1;
if (bit_is_clear(PINB, 0) && ++sw == 1) break;
wdt_reset();
} while (rb == 1024); /* Repeat until all data read */
}
while (FifoCt) ; /* Wait for FIFO empty */
OCR1A = 128; OCR1B = 128;
return res;
}
static
void delay500 (void)
{
TCCR1 = 0; GTCCR = 0; /* Stop TC1 */
TCCR0B = 0; TCCR0A = 0; /* Stop TC0 */
wdt_reset();
WDTCR = _BV(WDE) | _BV(WDIE) | 0b101; /* Enable WDT interrupt in timeout of 0.5s */
set_sleep_mode(SLEEP_MODE_PWR_DOWN); /* Enter power down mode */
sleep_mode();
WDTCR = _BV(WDE) | 0b110; /* Enable WDT reset in timeout of 1s */
}
//--------------------------------------------------------------------------
// USI functions for I2C slave
// copied from Axel Gartner, http://www.mikrocontroller.net/topic/38917
#define USI_DATA USIDR
#define USI_STATUS USISR
#define USI_CONTROL USICR
#define USI_ADDRESS 0x55
#define NONE 0
#define ACK_PR_RX 1
#define BYTE_RX 2
#define ACK_PR_TX 3
#define PR_ACK_TX 4
#define BYTE_TX 5
#define DDR_USI DDRB
#define PORT_USI PORTB
#define PIN_USI PINB
#define PORT_USI_SDA PORTB0
#define PORT_USI_SCL PORTB2
volatile uint8_t COMM_STATUS = NONE;
void USI_init(void) {
// 2-wire mode; Hold SCL on start and overflow; ext. clock
USI_CONTROL |= (1<<USIWM1) | (1<<USICS1);
USI_STATUS = 0xf0; // write 1 to clear flags, clear counter
DDR_USI &= ~(1<<PORT_USI_SDA);
PORT_USI &= ~(1<<PORT_USI_SDA);
DDR_USI |= (1<<PORT_USI_SCL);
PORT_USI |= (1<<PORT_USI_SCL);
// startcondition interrupt enable
USI_CONTROL |= (1<<USISIE);
}
SIGNAL(SIG_USI_START) {
uint8_t tmpUSI_STATUS;
tmpUSI_STATUS = USI_STATUS;
COMM_STATUS = NONE;
// Wait for SCL to go low to ensure the "Start Condition" has completed.
// otherwise the counter will count the transition
while ( (PIN_USI & (1<<PORT_USI_SCL)) );
USI_STATUS = 0xf0; // write 1 to clear flags; clear counter
// enable USI interrupt on overflow; SCL goes low on overflow
USI_CONTROL |= (1<<USIOIE) | (1<<USIWM0);
}
volatile unsigned char usi_rx_data = 0;
SIGNAL(SIG_USI_OVERFLOW) {
uint8_t BUF_USI_DATA = USI_DATA;
switch(COMM_STATUS) {
case NONE:
if (((BUF_USI_DATA & 0xfe) >> 1) != USI_ADDRESS) { // if not receiving my address
// disable USI interrupt on overflow; disable SCL low on overflow
USI_CONTROL &= ~((1<<USIOIE) | (1<<USIWM0));
}
else { // else address is mine
DDR_USI |= (1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
if (BUF_USI_DATA & 0x01) COMM_STATUS = ACK_PR_TX; else COMM_STATUS = ACK_PR_RX;
}
break;
case ACK_PR_RX:
DDR_USI &= ~(1<<PORT_USI_SDA);
COMM_STATUS = BYTE_RX;
break;
case BYTE_RX:
/* Save received byte here! ... = USI_DATA*/
usi_rx_data = USI_DATA;
DDR_USI |= (1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
COMM_STATUS = ACK_PR_RX;
break;
case ACK_PR_TX:
/* Put first byte to transmit in buffer here! USI_DATA = ... */
PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out
COMM_STATUS = BYTE_TX;
break;
case PR_ACK_TX:
if(BUF_USI_DATA & 0x01) {
COMM_STATUS = NONE; // no ACK from master --> no more bytes to send
}
else {
/* Put next byte to transmit in buffer here! USI_DATA = ... */
PORT_USI |= (1<<PORT_USI_SDA); // transparent for shifting data out
DDR_USI |= (1<<PORT_USI_SDA);
COMM_STATUS = BYTE_TX;
}
break;
case BYTE_TX:
DDR_USI &= ~(1<<PORT_USI_SDA);
PORT_USI &= ~(1<<PORT_USI_SDA);
USI_STATUS = 0x0e; // reload counter for ACK, (SCL) high and back low
COMM_STATUS = PR_ACK_TX;
break;
}
USI_STATUS |= (1<<USIOIF); // clear overflowinterruptflag, this also releases SCL
}
void USI_disable(void) {
USI_CONTROL =0;
}
/*-----------------------------------------------------------------------*/
/* Main */
int main (void)
{
unsigned char count;
MCUSR = 0; /* Clear WDRF in MCUSR */
/* Write logical one to WDCE and WDE */
WDTCR |= (1<<WDCE) | (1<<WDE);
/* Turn off WDT */
WDTCR = 0x00;
PORTB = 0b111011; /* Initialize port: - - H H H I H P */
DDRB = 0b111010;
USI_init();
sei();
while(usi_rx_data == 0); // wait until songnumber received (1-255)
USI_disable();
PORTB = 0b111011; /* Initialize port: - - H H H L H P */
DDRB = 0b111110;
pf_mount(&Fs);
pf_opendir(&Dir, "");
count = 0;
WDTCR = _BV(WDE) | 0b110; /* Enable WDT reset in timeout of 1s */
for(;;)
{
pf_readdir(&Dir, &Fno);
if( Fno.fname[0] == 0)
{
while(1);
}
if( Fno.fname[0] && (!(Fno.fattrib & (AM_DIR|AM_HID))) && strstr(Fno.fname, ".WAV") )
{
count++;
}
if(count == usi_rx_data)
{
play(Fno.fname);
while(1);
}
}
}
Etant complétement débutant, je ne comprends pas comment lancer le morceau que l'on souhaite via une commande I2C dans un sketch arduino....
Donc si quelqu'un pouvait me dire le truc ou me renvoyer vers un tuto je lui en serait reconnaissant ^^
Merci à vous.