Supponiamo che io abbia un cavo UTP sulla trentina di metri che mi colleghi un convertitore USB-rs485 ad un max485 sul mio arduino, vorrei usare questa stessa linea per la programmazione dell'ATmega.
Sappiamo che questo standard è un half-duplex, quindi per ricevere devo avere sui pin 2,3 del max uno stato basso e viceversa per inviare..
Ora, il convertitore usb dovrebbe comportarsi così: sto in ascolto->devo inviare qualcosa?allora mi metto in trasmissione->torno di nuovo in ascolto(e lo fa)
Ma non il max montato sull'arduino. O meglio, non se non glielo dico esplicitamente io da codice.
Oltre ad usare lo standard 422 che implementa due linee separate e sempre differenziali per ogni direzione della trasmissione, c'è un modo per raggirare questo problema?
Come faccio a scrivere sul micro che quando lo programmo, se riceve deve impostare a livello basso un determinato piedino e viceversa quando trasmette?
(Sto dando per scontato che quando programmo un ATmega oltre a mandargli dati devo riceverli anche..)
Hai dimenticato che l'Atmega328 in remoto deve essere resettato, altrimenti non può essere avviato il bootloader per ricevere lo sketch dalla seriale e scriverlo in Flash.
sciorty:
Momento,momento,moomeeento
Perciò che idea avete riguardo il fatto che devo alternare lo stato dei 2 pin del max durante la fase di cariamento?
Edit: modificare il bootloader.. e che ci scrivo?
Le istruzioni in C
A parte gli scherzi, che ci vuoi scrivere? Un digitalWrite sul pin a cui hai collegato i 2 pin del Max485 in modo da mettere il chip in ricezione, poi lasci il resto del bootloader inalterato. In questo modo al reset, il bootloader imposta il Max in ricezione e poi riceve lo sketch. Secondo me funziona.
Ma durante la fase di caricamento l'atmega non invia anche dei dati oltre che riceverli? non so, roba tipo handshake.. anche perchè sulla scheda vedo che si accendono entrambi i led!
Per il reset dovrei farcela: mettiamo che la sezione del cavo utp sia 1mm la resistenza è di 19,5ohm/km, e mettendo proprio per assurdo che il pin reset assorba 1A calcolo una caduta sul cavo di 1V e qualcosa.. se non sto sbagliando..
sciorty:
Ma durante la fase di caricamento l'atmega non invia anche dei dati oltre che riceverli? non so, roba tipo handshake.. anche perchè sulla scheda vedo che si accendono entrambi i led!
Sì, devi analizzare il codice dell'Optiboot e modificarlo in modo che ogni volta che deve ricevere o che deve trasmettere sulla seriale venga settato il Max nel corretto stato.
Per il reset dovrei farcela: mettiamo che la sezione del cavo utp sia 1mm la resistenza è di 19,5ohm/km, e mettendo proprio per assurdo che il pin reset assorba 1A calcolo una caduta sul cavo di 1V e qualcosa.. se non sto sbagliando..
sciorty:
Ma durante la fase di caricamento l'atmega non invia anche dei dati oltre che riceverli? non so, roba tipo handshake.. anche perchè sulla scheda vedo che si accendono entrambi i led!
Sì, devi analizzare il codice dell'Optiboot e modificarlo in modo che ogni volta che deve ricevere o che deve trasmettere sulla seriale venga settato il Max nel corretto stato.
Non so proprio dove mettere mani, cioè non so neanche dove risiedano questi codici
Se i miei calcoli erano giusti avrei potuto usare la rs232 anche se tirata per il collo, mi sarei risparmiato i 20 euro del convertitore usbrs485 =(
sciorty:
Per il reset dovrei farcela: mettiamo che la sezione del cavo utp sia 1mm la resistenza è di 19,5ohm/km, e mettendo proprio per assurdo che il pin reset assorba 1A calcolo una caduta sul cavo di 1V e qualcosa.. se non sto sbagliando..
Posso dedurre sia da cercare in questa zona.. (?):
/* Forever loop */
 for (;;) {
  /* get character from UART */
  ch = getch();
  if(ch == STK_GET_PARAMETER) {
   unsigned char which = getch();
   verifySpace();
   if (which == 0x82) {
/*
* Send optiboot version as "minor SW version"
*/
putch(OPTIBOOT_MINVER);
   } else if (which == 0x81) {
 putch(OPTIBOOT_MAJVER);
   } else {
/*
* GET PARAMETER returns a generic 0x03 reply for
    * other parameters - enough to keep Avrdude happy
*/
putch(0x03);
   }
  }
  else if(ch == STK_SET_DEVICE) {
   // SET DEVICE is ignored
   getNch(20);
  }
  else if(ch == STK_SET_DEVICE_EXT) {
   // SET DEVICE EXT is ignored
   getNch(5);
  }
  else if(ch == STK_LOAD_ADDRESS) {
   // LOAD ADDRESS
   uint16_t newAddress;
   newAddress = getch();
   newAddress = (newAddress & 0xff) | (getch() << 8);
#ifdef RAMPZ
   // Transfer top bit to RAMPZ
   RAMPZ = (newAddress & 0x8000) ? 1 : 0;
#endif
   newAddress += newAddress; // Convert from word address to byte address
   address = newAddress;
   verifySpace();
  }
  else if(ch == STK_UNIVERSAL) {
   // UNIVERSAL command is ignored
   getNch(4);
   putch(0x00);
  }
  /* Write memory, length is big endian and is in bytes */
  else if(ch == STK_PROG_PAGE) {
   // PROGRAM PAGE - we support flash programming only, not EEPROM
   uint8_t *bufPtr;
   uint16_t addrPtr;
   getch(); /* getlen() */
   length = getch();
   getch();
   // If we are in RWW section, immediately start page erase
   if (address < NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
   // While that is going on, read in page contents
   bufPtr = buff;
   do *bufPtr++ = getch();
   while (--length);
   // If we are in NRWW section, page erase has to be delayed until now.
   // Todo: Take RAMPZ into account
   if (address >= NRWWSTART) __boot_page_erase_short((uint16_t)(void*)address);
   // Read command terminator, start reply
   verifySpace();
   // If only a partial page is to be programmed, the erase might not be complete.
   // So check that here
   boot_spm_busy_wait();
#ifdef VIRTUAL_BOOT_PARTITION
   if ((uint16_t)(void*)address == 0) {
    // This is the reset vector page. We need to live-patch the code so the
    // bootloader runs.
    //
    // Move RESET vector to WDT vector
    uint16_t vect = buff[0] | (buff[1]<<8);
    rstVect = vect;
    wdtVect = buff[8] | (buff[9]<<8);
    vect -= 4; // Instruction is a relative jump (rjmp), so recalculate.
    buff[8] = vect & 0xff;
    buff[9] = vect >> 8;
    // Add jump to bootloader at RESET vector
    buff[0] = 0x7f;
    buff[1] = 0xce; // rjmp 0x1d00 instruction
   }
#endif
   // Copy buffer into programming buffer
   bufPtr = buff;
   addrPtr = (uint16_t)(void*)address;
   ch = SPM_PAGESIZE / 2;
   do {
    uint16_t a;
    a = *bufPtr++;
    a |= (*bufPtr++) << 8;
    __boot_page_fill_short((uint16_t)(void*)addrPtr,a);
    addrPtr += 2;
   } while (--ch);
   // Write from programming buffer
   __boot_page_write_short((uint16_t)(void*)address);
   boot_spm_busy_wait();
#if defined(RWWSRE)
   // Reenable read access to flash
   boot_rww_enable();
#endif
  }
  /* Read memory block mode, length is big endian. */
  else if(ch == STK_READ_PAGE) {
   // READ PAGE - we only read flash
   getch(); /* getlen() */
   length = getch();
   getch();
   verifySpace();
#ifdef VIRTUAL_BOOT_PARTITION
   do {
    // Undo vector patch in bottom page so verify passes
    if (address == 0)   ch=rstVect & 0xff;
    else if (address == 1) ch=rstVect >> 8;
    else if (address == 8) ch=wdtVect & 0xff;
    else if (address == 9) ch=wdtVect >> 8;
    else ch = pgm_read_byte_near(address);
    address++;
    putch(ch);
   } while (--length);
#else
#ifdef __AVR_ATmega1280__
//Â Â Â do putch(pgm_read_byte_near(address++));
//Â Â Â while (--length);
   do {
    uint8_t result;
    __asm__ ("elpm %0,Z\n":"=r"(result):"z"(address));
    putch(result);
    address++;
   }
   while (--length);
#else
   do putch(pgm_read_byte_near(address++));
   while (--length);
#endif
#endif
  }
  /* Get device signature bytes */
  else if(ch == STK_READ_SIGN) {
   // READ SIGN - return what Avrdude wants to hear
   verifySpace();
   putch(SIGNATURE_0);
   putch(SIGNATURE_1);
   putch(SIGNATURE_2);
  }
  else if (ch == 'Q') {
   // Adaboot no-wait mod
   watchdogConfig(WATCHDOG_16MS);
   verifySpace();
  }
  else {
   // This covers the response to commands like STK_ENTER_PROGMODE
   verifySpace();
  }
  putch(STK_OK);
 }
Intorno alla riga 292, metti l'attivazione del chip in ricezione.
 // Adaboot no-wait mod
 ch = MCUSR;
 MCUSR = 0;
 if (!(ch & _BV(EXTRF))) appStart();
***************** QUIÂ ************
#if LED_START_FLASHES > 0
Stavo vedendo la funzione flash_led, che dovrebbe essere quella che viene ripetuta due volte per segnalare l'inizio di caricamento dello sketch facendo accendere il led13. Pensavo che magari avrei potuto prenderne spunto e semplicemente andare a modificare la porta :
void flash_led(uint8_t count) {
 do {
  TCNT1 = -(F_CPU/(1024*16));
  TIFR1 = _BV(TOV1);
  while(!(TIFR1 & _BV(TOV1)));
#ifdef __AVR_ATmega8__
  LED_PORT ^= _BV(LED);
#else
  LED_PIN |= _BV(LED);
#endif
  watchdogReset();
 } while (--count);
}
Ma sono solo arrivato a capire che se il micro non è un atmega 8 fa un operazione or tra LED_PIN e la funzione _BV(LED)..
Ma tutta queste variabili cosa contengono? Non trovo le assegnazioni!
Per mettere in input un pin, devi prima vedere dalla piedinatura del microcontrollore a quale porta appartiene e poi imposti il suo bit.
Ad esempio, il pin D10 di Arduino è il piedino PB3, quindi porta "B", bit "3".
Ora, sapendo questo, col link che ti ho dato, vedi che il registro DDx regola la direzione dei pin di una porta.
Quindi se vuoi mettere quel pin come output, devi mettere a 1 il bit 3.
DDRB |= (1<<3);
Adesso lo stato del pin lo regoli con il registro PORTx corrispondente, quindi PORTB.
1 sul bit 3 mette "HIGH" quel pin, 0 lo mette LOW:
PORTB |= (1<<3); //mette HIGH
PORTB &= ~(1<<3); //mette LOW