Пн ноя 06, 2023 22:31:10
/*
* atmega32_slave_i2c_bootloader.c
*
* Created: 31.10.2023 21:11:47
* Author : dmitr
*/
#include <avr/io.h>
#include <avr/boot.h>
#include "TWI_slave.h"
#include "systick.h"
#include "bootloader_config.h"
#include <avr/interrupt.h>
#include <compat/twi.h>
#include <stdio.h>
#include <inttypes.h>
#include <util/delay.h>
#include <string.h>
#include <avr/pgmspace.h>
#define LEN 32
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
#define BOOTLOADER_GET_VERSION 0x01
#define BOOTLOADER_IS_BOOTLOADER_MODE 0x02
#define BOOTLOADER_START_FLASH 0x10
#define BOOTLOADER_SEND_FLASH_CHUNK 0x11
#define BOOTLOADER_GET_LAST_TRANSITION_STATUS 0x12
#define BOOTLOADER_END_FLASH 0x13
#define BOOTLOADER_BOOT_TO_PROGRAM 0x20
/* device compatibility: */
#ifndef GICR /* ATMega*8 don't have GICR, use MCUCR instead */
# define GICR MCUCR
#endif
/* ---------- */
unsigned char regaddr; // Store the Requested Register Address
unsigned char regdata; // Store the Register Address Data
char buffer[LEN];
register unsigned char IT asm("r16");
volatile unsigned char done;
volatile unsigned char IDX;
static void jump_to_main_program() __attribute__((__noreturn__));
void USART_Init( unsigned int ubrr)
{
/*Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
//Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 1stop bit */
UCSRC = (1<<URSEL)|(3<<UCSZ0);
}
void USART_Deinit() {
UCSRB = (0<<RXEN)|(0<<TXEN);
}
static int uart_putchar(char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r', stream);
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
return 0;
}
inline void clearStr(char* str)
{
for(IT=0;IT<LEN;IT++)
str[IT]=0;
}
ISR(USART_RXC_vect)
{
char bf= UDR;
buffer[IDX]=bf;
IDX++;
if (bf == ':' || IDX >= LEN)
{
IDX=0;
done=1;
}
}
void int_out_send_interrupt() {
BOOTLOADER_CONFIG_INT_OUT_PORT |= (1<<BOOTLOADER_CONFIG_INT_OUT_PIN);
_delay_us(100);
BOOTLOADER_CONFIG_INT_OUT_PORT &= ~(1<<BOOTLOADER_CONFIG_INT_OUT_PIN);
_delay_us(100);
}
void jump_to_main_program() {
cli();
int_out_send_interrupt();
USART_Deinit();
sysTimerDeinit();
GICR |= (1<<IVCE);
GICR &= ~(1<<IVSEL);
asm("jmp 0x0000");
}
void TWI_Act_On_Failure_In_Last_Transmission ();
void IO_Init() {
BOOTLOADER_CONFIG_INT_OUT_DDR |= (1<<BOOTLOADER_CONFIG_INT_OUT_PIN);
BOOTLOADER_CONFIG_INT_OUT_PORT &= ~(1<<BOOTLOADER_CONFIG_INT_OUT_PIN);
//TWI Pull UP
PORTC |= ((1<<PINC0) | (1<<PINC1));
}
void boot_program_page (uint32_t page, uint8_t *buf)
{
uint16_t i;
uint8_t sreg;
// Disable interrupts.
sreg = SREG;
cli();
eeprom_busy_wait ();
boot_page_erase (page);
boot_spm_busy_wait (); // Wait until the memory is erased.
for (i=0; i<SPM_PAGESIZE; i+=2)
{
// Set up little-endian word.
uint16_t w = *buf++;
w += (*buf++) << 8;
boot_page_fill (page + i, w);
}
boot_page_write (page); // Store buffer in flash page.
boot_spm_busy_wait(); // Wait until the memory is written.
// Reenable RWW-section again. We need this if we want to jump back
// to the application after bootloading.
boot_rww_enable ();
// Re-enable interrupts (if they were ever enabled).
SREG = sreg;
}
int main(void)
{
uint8_t temp=GICR;
GICR|=(1<<IVCE);
GICR|=(1<<IVSEL);
IO_Init();
sysTimerInit();
USART_Init(MYUBRR);
TWI_Slave_Initialise(BOOTLOADER_CONFIG_I2C_SLAVE_ADDRESS);
unsigned char messageBuf[TWI_BUFFER_SIZE];
unsigned char flash_page_buf[SPM_PAGESIZE];
uint32_t bootloader_react_millis = millis();
uint8_t bootloader_countdown = 1;
uint8_t quit_from_bootloader = 0;
uint8_t flash_allowed = 0;
uint8_t flash_last_transition_status_ok = 0;
uint16_t flash_page_start_address = 0;
uint16_t page_received_cs = 0;
uint16_t page_received_cs_calc = 0;
int_out_send_interrupt();
sei();
/* Replace with your application code */
printf("Send any I2C command within 1 sec to get into bootloader mode\n");
while (1)
{
// Check if the TWI Transceiver has completed an operation.
if ( ! TWI_Transceiver_Busy() )
{
// Check if the last operation was successful
if ( TWI_statusReg.lastTransOK )
{
// Check if the last operation was a reception
if ( TWI_statusReg.RxDataInBuf )
{
// byte 0 - cmd
// byte 1 - data
TWI_Get_Data_From_Transceiver(messageBuf, TWI_BUFFER_SIZE);
// Check if the last operation was a reception as General Call
if ( TWI_statusReg.genAddressCall )
{
// Not needed to react on broadcast address
// Put data received out to PORTB as an example.
//PORTB = messageBuf[0];
}
else // Ends up here if the last operation was a reception as Slave Address Match
{
// Example of how to interpret a command and respond.
regaddr = messageBuf[0];
bootloader_countdown = 0;
printf("Bootloader mode\n");
switch(regaddr) {
case BOOTLOADER_GET_VERSION:
printf("Firmware version is %s \n", BOOTLOADER_CONFIG_FIRMWARE_VERSION_STRING);
TWI_Start_Transceiver_With_Data(BOOTLOADER_CONFIG_FIRMWARE_VERSION_STRING, sizeof(BOOTLOADER_CONFIG_FIRMWARE_VERSION_STRING));
break;
case BOOTLOADER_IS_BOOTLOADER_MODE:
memset(messageBuf, 0, sizeof(messageBuf));
messageBuf[0] = BOOTLOADER_IS_BOOTLOADER_MODE;
messageBuf[1] = 1;
TWI_Start_Transceiver_With_Data(messageBuf, 2);
case BOOTLOADER_START_FLASH:
flash_allowed = 1;
flash_page_start_address = 0;
break;
case BOOTLOADER_SEND_FLASH_CHUNK:
if (!flash_allowed) break;
flash_last_transition_status_ok = 0;
page_received_cs = 0;
for(int i = 0; i < TWI_BUFFER_SIZE-2; i++) page_received_cs += messageBuf[i];
page_received_cs_calc = (uint16_t)(messageBuf[TWI_BUFFER_SIZE-2]<<8) | (uint16_t)(messageBuf[TWI_BUFFER_SIZE-1]);;
if (page_received_cs_calc - page_received_cs == 0) {
flash_page_start_address = (uint16_t)(messageBuf[1]<<8) | (uint16_t)(messageBuf[2]);
for (int i = 0; i < SPM_PAGESIZE; i++) flash_page_buf[i] = messageBuf[i+3];
boot_program_page((uint32_t)flash_page_start_address, flash_page_buf);
flash_last_transition_status_ok = 1;
}
int_out_send_interrupt();
break;
case BOOTLOADER_END_FLASH:
flash_page_start_address = 0;
flash_allowed = 0;
break;
case BOOTLOADER_BOOT_TO_PROGRAM:
quit_from_bootloader = 1;
break;
default:
break;
}
}
}
else // Ends up here if the last operation was a transmission
{
asm("nop"); // Put own code here.
}
// Check if the TWI Transceiver has already been started.
// If not then restart it to prepare it for new receptions.
if ( ! TWI_Transceiver_Busy() )
{
TWI_Start_Transceiver();
}
}
else // Ends up here if the last operation completed unsuccessfully
{
TWI_Act_On_Failure_In_Last_Transmission();
}
}
if (quit_from_bootloader) break;
if (bootloader_countdown && (millis()-bootloader_react_millis>1000))
break;
}
jump_to_main_program();
}
void TWI_Act_On_Failure_In_Last_Transmission ()
{
//PORTB = TWIerrorMsg;
TWI_Get_State_Info();
TWI_Start_Transceiver();
//return TWIerrorMsg;
}
Вс ноя 12, 2023 01:59:25