Guest Razvan Marinovici Posted May 22, 2017 Share Posted May 22, 2017 Salut, Nu am sa incep cu povestea, vreau doar sa spun ca am inceput sa lucrez la o extensie pentru a face debug pe Arduino din Atmel Studio. Nu ma refer la debugger extern, ma refer la software debugger. Sunt unele limitari dar pentru multe proiecte cred ca este suficient. As avea nevoie de ajutor de la voi, unu pentru teste, doi pentru ajutor la development, extensia va fi free deci nu va ganditi la castiguri. https://www.youtube.com/watch?v=p_YvdBPmX_E - Ram change / debug / variable change https://www.youtube.com/watch?v=HBGGGCVuaxc - EEPROM change - single step / continue running ..... https://www.youtube.com/watch?v=6AgQ8sfcUJk - Aplicatie de debug externa AS. Daca e cineva interesat va rog sa imi spuneti, si vedem cum facem sa expun codul si sa adaug useri la repo. Link to comment
Liviu M Posted May 22, 2017 Share Posted May 22, 2017 Salut, curajos proiect , felicitari! La partea de munca nu ma bag, dar am o idee despre modul de colaborare - iti faci cont pe github.com si urci proiectul acolo. Daca cineva vrea sa contribuie, il cloneaza, face modificarile si ti le trimite sa le aplici prin pull request-uri. In modul asta pastrezi controlul asupra a ce intra in proiect. Asta daca proiectul ramane deschis. Se poate si closed, da' e ceva mai mult de scris si de pe tableta.. Link to comment
Guest Razvan Marinovici Posted May 23, 2017 Share Posted May 23, 2017 Multumesc, Ideea de la care am plecat, este urmatoarea, am un Arduino si un USB, vreau sa fac debug, optiunile ar fi- Visual Micro (am licenta), personal nu imi place, prea complicat, si nu poti face debug in adevaratul sens. + este prea mare (ma refer la marimea codului)- GDB - la fel prea mare pentru mine, cam 4k flash si mult ram. Cerintele pe care le-am pus de la inceput au fost - USB to Arduino si atat pentru folosire- Configurabil (folosesc strict ce am nevoie), impact asupra spatiului folosit (flash si ram)- Marimea codului cat mai mica- RAM ocupat cat mai putin.- Posibilitatea de a avea serverul de debug in bootloader. Dupa parerea mea am reusit partial. Posibilitatea de a avea cel putin citire variabile (ram) in doar 360 bytes (flash) si 7 RAM este ok, poate fi inclus in optiboot. Codul este pe GIT privat momentan, vroiam sa stiu daca sunt persoane care doresc sa ajute, in caz negativ il voi face public cand il termin complet pentru prima versiune. Lucrez la el in timpul liber de aici si nevoia de ajutor. Are 5 proiecte in el - Codul nativ (serverul de debug din Arduino) - Clientul pentru debug (librarie pentru comunicarea cu serverul din Arduino) - Aplicatie Consola - Extensia din AS - Aplicatia pentru debug externa AS Este de lucru cam la toate cate putin - codul nativ momentan este continut in trei fisiere header. (doua pentru debug si unul pentru printf) - As vrea sa il descompun in fisiere separate pentru fiecare device in parte ("Atmega328", "Atmega168" .... ) - Unele valori sunt hardcoded cum ar fi viteza UART - printf momentan este inclus mereu, ar trebui sa il incadrez in define's si sa adaug optiune la build pentru el. - Nu are suport pentru Error Check (viteza UART este 500k daca aleg alta viteza va fi problematic), aici e mai complicat, daca vreau suport pentru CRC am 3 optiuni - Salvez tot buffer-ul si calculez un CRC pe el inainte sa il folosesc, problemele aici sunt: ce marime de buffer e suficienta (pot scrie toata memoria RAM asta inseamna un buffer cel putin la fel de mare ca marimea RAM-ului, nu are sens), daca aleg o marime de buffer mai mica tot e problematic pentru ca este in conflict cu una din cerinte - Procesez cate un byte sau 2, 3 pe care ii validez inainte sa trimit alte date. - Extensia, cam 90% gata, mai am exceptii din cand in cand trebuie sa vad de unde vin (e complicat tare sistemul) - Foloseste simulatorul pentru a face debug, practic suprascriu / monitorizez datele din simulator si las AS + Simulatorul sa afiseze / proceseze datele afisate, e complicat de controlat toate 3 lucruri in mod coerent (Serverul de Debug Arduino, Simulatorul, Serverul de Debug din AS) - Trebuie sa includ codul nativ in proiect, astfel incat la install sa poata fi folosit. - Aplicatia externa pentru debug, aici mai am de lucru la procesarea fisierului ELF si a datelor DWARF pentru debug. - Aplicatia consola, a fost folosita initial pentru teste, ar fi un nice to have nu tin neaparat la ea Toate proiectele sunt in C# / .NET 4.6 (in afara de codul nativ pentru Arduino) Mai jos este codul nativ pe care as vrea sa il despart in functionalitatea de server si implementarile specifice pentru device-uri. /* * debug.h * * Created: 2/27/2017 10:38:31 AM * Author: razvanm */ #ifndef DEBUG_H_ #define DEBUG_H_ #include <stdint.h> #include <avr/io.h> #include <avr/common.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include "debug_defs.h" #define DEBUG_PROTOCOL_VERSION 0x01 #ifdef __cplusplus extern "C" { #endif // This should be used to call the debug function // It will force the compiler to place the PC on stack and not optimize the call // otherwise we could be in a situation where we are breaking in method_a, yet the compiler // has optimized the stack to return directly to the calling method // Normal stack // PC - Parent // PC - method_a // Debug method // Optimized stack - we can't tell we were called from method_a // PC - Parent - method_a - optimized away // Debug method - return directly to parent #ifdef DEBUG #define DEBUG_BRK asm volatile ("call dbg_brk"); #else #define DEBUG_BRK #endif #ifdef __cplusplus } #endif #ifndef EEWE #define EEWE (1) #endif #define AVR8_SWINT_PIN (PORTD2) #define AVR8_SWINT_INTMASK (INT0) #define AVR8_INT_SOURCE INT0_vect ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // This assumes the following for now // - Clock - 16Mhz // - 16 Bit PC / STACK register sizes // - 16 Bit pointers // - At most 64k flash // --------------- // - Basically an ATmega328 ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // MINIMIZE_RAM will force inline everything, so we don't have to push / pop registers between calls // it will however increase the flash size, we might even figure out a way to optimize the ram structure ???? // MINIMIZE_FLASH will use the stack to push / pop registers when needed, if the stack is full, this will cause issues. #define MINIMIZE_FLASH ////////////////////////////////////////////////////////////////////////// // THE CAPABILITIES WE WANT TO HAVE IN THE DEBUGGER // By default we only have "Read ram" without saving the registers ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // Enable the functionality to change the RAM memory //CAPS_RAM_WRITE ////////////////////////////////////////////////////////////////////////// // Enable high speed UART (500000) this maps perfectly with 4,8,16,20Mhz crystals // it also allows us to read / write fast from / to memory //CAPS_UART_HIGH_SPEED ////////////////////////////////////////////////////////////////////////// // Save the registers (R0...R31), the return PC address (from stack) and the stack pointer //CAPS_SAVE_CTX ////////////////////////////////////////////////////////////////////////// // Enable flash read so we can read the program from memory //CAPS_FLASH_READ ////////////////////////////////////////////////////////////////////////// // Enable flash write so we can change the program memory (AVR's support this only from bootloader) //CAPS_FLASH_WRITE ////////////////////////////////////////////////////////////////////////// // Enable EEPROM read //CAPS_EEPROM_READ ////////////////////////////////////////////////////////////////////////// // Enable EEPROM write //CAPS_EEPROM_WRITE ////////////////////////////////////////////////////////////////////////// // Enable code execution / method invocation, not done for now //CAPS_EXECUTE ////////////////////////////////////////////////////////////////////////// // Enable single step support //CAPS_SINGLE_STEP ////////////////////////////////////////////////////////////////////////// // Read the debug structure information in cases where we don't have access // to the compiled program (elf file). For example when the debugger is // included in the bootloader, we don't have the bootloader file at our disposal // we need to know the location of the debug context, the structure will be based // on the CAPS enabled and retrieved when the debugging starts //CAPS_DBG_CTX_ADDR #if defined(MINIMIZE_FLASH) && defined(MINIMIZE_RAM) #error "Cannot minimize flash an ram at the same time, please choose only one" #endif #define INLINE static inline #if defined(MINIMIZE_RAM) #define ATTRIBUTES __attribute__((always_inline, optimize("-Os"))) #elif defined(MINIMIZE_FLASH) #define ATTRIBUTES __attribute__ ((optimize("-Os"))) #else #define ATTRIBUTES __attribute__ ((optimize("-Os"))) #endif #ifndef _BV #define _BV(v) (1 << (v)) #endif #ifdef CAPS_DISABLE_TIMERS #define CAPS_FLAG_DISABLE_TIMERS _BV(CAPS_DISABLE_TIMERS_BIT) #ifndef CAPS_SAVE_POWER_REG #define CAPS_SAVE_POWER_REG #endif #else #define CAPS_FLAG_DISABLE_TIMERS 0 #endif #ifdef CAPS_SINGLE_STEP #define CAPS_FLAG_SINGLE_STEP _BV(CAPS_SINGLE_STEP_BIT) #ifndef CAPS_SAVE_CTX #define CAPS_SAVE_CTX #endif #else #define CAPS_FLAG_SINGLE_STEP 0 #endif #ifdef CAPS_UART_HIGH_SPEED ////////////////////////////////////////////////////////////////////////// // BAUD PRESCALLER Used by the debug functionality, this will make 500k communication // TODO Calculate this based on the CPU frequency, for now assume 16Mhz #define BAUD_PRESCALLER 1 #define CAPS_FLAG_UART_HIGH_SPEED _BV(CAPS_UART_HIGHSPEED_BIT) #else #define CAPS_FLAG_UART_HIGH_SPEED 0 #endif #ifdef CAPS_SAVE_CTX #ifndef CAPS_DBG_CTX_ADDR #define CAPS_DBG_CTX_ADDR #endif #define CAPS_FLAG_SAVE_CTX _BV(CAPS_SAVE_CONTEXT_BIT) #else #define CAPS_FLAG_SAVE_CTX 0 #endif #ifdef CAPS_RAM_WRITE #define CAPS_FLAG_RAM_WRITE _BV(CAPS_RAM_W_BIT) #else #define CAPS_FLAG_RAM_WRITE 0 #endif #ifdef CAPS_FLASH_READ #define CAPS_FLAG_FLASH_READ _BV(CAPS_FLASH_R_BIT) #else #define CAPS_FLAG_FLASH_READ 0 #endif #ifdef CAPS_FLASH_WRITE #define CAPS_FLAG_FLASH_WRITE _BV(CAPS_FLASH_W_BIT) #else #define CAPS_FLAG_FLASH_WRITE 0 #endif #ifdef CAPS_EEPROM_READ #define CAPS_FLAG_EEPROM_READ _BV(CAPS_EEPROM_R_BIT) #else #define CAPS_FLAG_EEPROM_READ 0 #endif #ifdef CAPS_EEPROM_WRITE #define CAPS_FLAG_EEPROM_WRITE _BV(CAPS_EEPROM_W_BIT) #else #define CAPS_FLAG_EEPROM_WRITE 0 #endif #ifdef CAPS_EXECUTE #define CAPS_FLAG_EXECUTE _BV(CAPS_EXECUTE_BIT) #else #define CAPS_FLAG_EXECUTE 0 #endif #ifdef CAPS_DBG_CTX_ADDR #define CAPS_FLAG_DBG_CTX_ADDR _BV(CAPS_DBG_CTX_ADDR_BIT) #else #define CAPS_FLAG_DBG_CTX_ADDR 0 #endif ////////////////////////////////////////////////////////////////////////// // The debug capabilities we have #define CAPS_0 _BV(CAPS_RAM_R_BIT) | CAPS_FLAG_RAM_WRITE | CAPS_FLAG_FLASH_READ | CAPS_FLAG_FLASH_WRITE | CAPS_FLAG_EEPROM_READ | CAPS_FLAG_EEPROM_WRITE | CAPS_FLAG_EXECUTE | CAPS_FLAG_DBG_CTX_ADDR #define CAPS_1 CAPS_FLAG_UART_HIGH_SPEED | CAPS_FLAG_SAVE_CTX | CAPS_FLAG_SINGLE_STEP | CAPS_FLAG_DISABLE_TIMERS #define DBG_FLAG_EXECUTING 0 #define DBG_FLAG_UART_HIGH_SPEED 1 #define DBG_SINGLE_STEP_ISR 2 #define DBG_WILL_SINGLE_STEP 3 #define INTERRUPT_FLAG_BIT 7 ////////////////////////////////////////////////////////////////////////// // Debug data sent when entering debug, so we know we are debugging and what capabilities we have const uint8_t DEBUG_INFO[] PROGMEM = {DEBUG_COM_KEY_0, DEBUG_COM_KEY_1, DEBUG_COM_KEY_2, DEBUG_COM_KEY_3, DEBUG_COM_KEY_4, DEBUG_PROTOCOL_VERSION, SIGNATURE_0, SIGNATURE_1, SIGNATURE_2, CAPS_0, CAPS_1, DEBUG_COM_DATA_FILLER}; typedef struct { uint8_t l; uint8_t h; } st_16bit_struct; typedef union { st_16bit_struct d8; uint16_t d16; } tu_uint16; typedef union { st_16bit_struct nibbles; uint16_t addr; uint8_t* ptr; } tu_puint8; typedef struct { tu_uint16 size; tu_puint8 buff; } t_mem_op_8; #ifdef CAPS_UART_HIGH_SPEED typedef struct { uint8_t ubrrh; uint8_t ubrrl; uint8_t ucsrc; uint8_t ucsrb; } t_uart_regs; #endif #if defined(CAPS_EEPROM_READ) || defined(CAPS_EEPROM_WRITE) typedef struct { uint16_t eear; #ifdef CAPS_EEPROM_WRITE uint8_t eedr; #endif } t_eeprom_regs; #endif #ifdef CAPS_SAVE_CTX typedef struct { uint8_t _registers[32]; tu_puint8 _stack_ptr; tu_uint16 _return_addr; } t_state_ctx; #endif #ifdef CAPS_SAVE_POWER_REG typedef struct { uint8_t prr; } t_power_regs; #endif ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // DEBUG CONTEXT STRUCTURE, Define everything we need here // so we know at build time how much ram we need, also the compiler can optimize the memory access with a base pointer and offset // It is important that the registers are in the first part of the structure // We are doing asm with offset loads, and the largest offset is 64 // So the registers must be in the first 64 bytes of the structure typedef struct { ////////////////////////////////////////////////////////////////////////// // Save registers / PC / stack pointer #ifdef CAPS_SAVE_CTX t_state_ctx registers; #endif ////////////////////////////////////////////////////////////////////////// // High speed UART #ifdef CAPS_UART_HIGH_SPEED t_uart_regs uart_regs; #endif ////////////////////////////////////////////////////////////////////////// // EEprom functionality #if defined(CAPS_EEPROM_READ) || defined(CAPS_EEPROM_WRITE) t_eeprom_regs eeprom_regs; #endif ////////////////////////////////////////////////////////////////////////// // Execute support #if defined(CAPS_EXECUTE) || defined(CAPS_UART_HIGH_SPEED) || defined(CAPS_SINGLE_STEP) uint8_t ctx_state; #endif #ifdef CAPS_SAVE_POWER_REG t_power_regs power_regs; #endif t_mem_op_8 mem_op; uint8_t tmp_u8; uint8_t status_reg; uint8_t watchdog; } t_dbg_context; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // We don't need the context to be initialized, we will initialize what we need manually // this way we give the user an option to remove the initialization code generated by GCC if they need that __attribute__((section(".noinit"))) t_dbg_context dbg_context; ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// __attribute__((used, optimize("-Os"))) void dbg_init(){ dbg_context.ctx_state = 0; } #ifdef CAPS_SAVE_POWER_REG INLINE ATTRIBUTES void dbg_save_power_reg(){ dbg_context.power_regs.prr = PRR; } INLINE ATTRIBUTES void dbg_restore_power_reg(){ PRR = dbg_context.power_regs.prr; } #endif #ifdef CAPS_DISABLE_TIMERS INLINE ATTRIBUTES void dbg_disable_timers(){ PRR &= ~(_BV(PRTIM0) | _BV(PRTIM1) | _BV(PRTIM2)); } #endif #ifdef CAPS_SINGLE_STEP INLINE ATTRIBUTES void dbg_enable_single_step(){ EICRA &= ~(_BV(ISC01) | _BV(ISC00)); DDRD |= _BV(AVR8_SWINT_PIN); /* set pin to output mode */ EIFR |= _BV(AVR8_SWINT_INTMASK); /* clear INTx flag */ EIMSK |= _BV(AVR8_SWINT_INTMASK); /* enable INTx interrupt */ PORTD &= ~_BV(AVR8_SWINT_PIN); /* make sure the pin is low */ } INLINE ATTRIBUTES void dbg_disable_single_step(){ EIMSK &= ~_BV(AVR8_SWINT_INTMASK); } #endif ////////////////////////////////////////////////////////////////////////// #ifdef CAPS_UART_HIGH_SPEED INLINE ATTRIBUTES void dbg_init_uart(){ UBRR0H = (uint8_t)(BAUD_PRESCALLER>>8); UBRR0L = (uint8_t)(BAUD_PRESCALLER); UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = ((1<<UCSZ00)|(1<<UCSZ01)); } INLINE ATTRIBUTES void dbg_save_uart_state(){ dbg_context.uart_regs.ubrrh = UBRR0H; dbg_context.uart_regs.ubrrl = UBRR0L; dbg_context.uart_regs.ucsrb = UCSR0B; dbg_context.uart_regs.ucsrc = UCSR0C; } INLINE ATTRIBUTES void dbg_restore_uart_state(){ UBRR0H = dbg_context.uart_regs.ubrrh; UBRR0L = dbg_context.uart_regs.ubrrl; UCSR0B = dbg_context.uart_regs.ucsrb; UCSR0C = dbg_context.uart_regs.ucsrc; } #endif ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// #ifdef CAPS_SAVE_CTX ////////////////////////////////////////////////////////////////////////// // Save registers //// Register save inspired from https://www.codeproject.com/articles/1037057/debugger-for-arduino INLINE ATTRIBUTES void dbg_save_registers(){ asm volatile ( "sts %[regs]+31, r31 \n\t" // R31 "in r31, __SREG__ \n\t" "cli \n\t" "sts %[statusaddr], r31 \n\t" // SREG "sts %[regs]+30, r30 \n\t" // R30 // Save registers from 0 to 27 inclusive "ldi r30, lo8(%[regs]) \n\t" // load with regs ptr "ldi r31, hi8(%[regs]) \n\t" // load with regs ptr Z "std z+29, r29 \n\t" "std z+28, r28 \n\t" "std z+27, r27 \n\t" "ldi r28, 0 \n\t" "ldi r29, 0 \n\t" "1: ld r27, y+ \n\t" "st z+, r27 \n\t" "cpi r28, 27 \n\t" "brne 1b \n\t" // Save PC "pop r15 \n\t" // Return ADDR HIGH "std z+35-27, r15 \n\t" "pop r16 \n\t" // Return ADDR LOW "std z+34-27, r16 \n\t" "push r16 \n\t" // Return ADDR LOW "push r15 \n\t" // Return ADDR HIGH // Save stack "in r15, __SP_L__ \n\t" "std z+32-27, r15 \n\t" "in r15, __SP_H__ \n\t" "std z+33-27, r15 \n\t" // And finally clear r1, the compiler expects this to be 0 "clr __zero_reg__ \n\t" :: [statusaddr] "i" (&dbg_context.status_reg), [regs] "i" (&dbg_context.registers) ); } INLINE ATTRIBUTES void dbg_restore_registers(){ asm volatile ( "ldi r30, lo8(%[regs]) \n\t" // load with regs ptr "ldi r31, hi8(%[regs]) \n\t" // load with regs ptr Z // Restore the registers from 0 to 27 (inclusive) "ldi r28, 0 \n\t" "ldi r29, 0 \n\t" "1: ld r27, z+ \n\t" "st y+, r27 \n\t" "cpi r28, 27 \n\t" "brne 1b \n\t" // Restore registers from 28 to 31 and the SREG register "ld r27, z \n\t" "ldd r28, z+28-27 \n\t" "ldd r29, z+29-27 \n\t" "ldd r30, z+30-27 \n\t" "lds r31, %[statusaddr] \n\t" "out __SREG__, r31 \n\t" "lds r31, %[regs]+31 \n\t" :: [statusaddr] "i" (&dbg_context.status_reg), [regs] "i" (&dbg_context.registers) ); } #endif ////////////////////////////////////////////////////////////////////////// #if defined(CAPS_EEPROM_READ) || defined(CAPS_EEPROM_WRITE) #ifdef CAPS_EEPROM_READ INLINE ATTRIBUTES uint8_t dbg_eeprom_read(uint16_t addr){ /* Wait for completion of previous write */ while(EECR & (1<<EEWE)); /* Set up address register */ EEAR = addr; /* Start eeprom read by writing EERE */ EECR |= (1<<EERE); /* Return data from Data Register */ return EEDR; } #endif #ifdef CAPS_EEPROM_WRITE INLINE ATTRIBUTES void dbg_eeprom_write(uint16_t addr, uint8_t data){ /* Wait for completion of previous write */ while(EECR & (1<<EEWE)); /* Set up address and Data Registers */ EEAR = addr; EEDR = data; /* Write logical one to EEMPE */ EECR |= (1<<EEMPE); /* Start eeprom write by setting EEWE */ EECR |= (1<<EEWE); } #endif #endif INLINE ATTRIBUTES void dbg_enter_debug(){ #ifdef CAPS_SAVE_POWER_REG dbg_save_power_reg(); #endif #ifndef CAPS_SAVE_CTX // Disable interrupts, we don't need / want any dbg_context.status_reg = SREG; cli(); #else // Disable the interrupts // Save the registers (we are doing a `context switch`) dbg_save_registers(); #endif } INLINE ATTRIBUTES void dbg_leave_debug(){ #ifdef CAPS_SAVE_POWER_REG dbg_restore_power_reg(); #endif #ifdef CAPS_SAVE_CTX // Context switch again dbg_restore_registers(); #else // Restore the status registers, this will enable interrupts if they were // enabled when we entered debug SREG = dbg_context.status_reg; #endif } INLINE ATTRIBUTES void dbg_disable_watchdog(){ dbg_context.watchdog = WDTCSR; // Disable watchdog WDTCSR ^= ~_BV(WDE); } INLINE ATTRIBUTES void dbg_restore_watchdog(){ WDTCSR = dbg_context.watchdog; } uint8_t dbg_get_ch(){ while(!(UCSR0A & (1<<RXC0))); return UDR0; } void dbg_put_ch(uint8_t data){ while(!(UCSR0A & (1<<UDRE0))); UDR0 = data; } INLINE ATTRIBUTES void dbg_read_mem_op(){ // 2 bytes - the address dbg_context.mem_op.buff.nibbles.h = dbg_get_ch(); dbg_context.mem_op.buff.nibbles.l = dbg_get_ch(); // Next 2 bytes the size to read dbg_context.mem_op.size.d8.h = dbg_get_ch(); dbg_context.mem_op.size.d8.l = dbg_get_ch(); } INLINE ATTRIBUTES void dbg_send_info(){ for(dbg_context.tmp_u8 = 0; dbg_context.tmp_u8 < sizeof(DEBUG_INFO); ++dbg_context.tmp_u8){ dbg_put_ch(pgm_read_byte_near(DEBUG_INFO + dbg_context.tmp_u8)); } } INLINE ATTRIBUTES void dbg_disable_interrupts(){ dbg_context.status_reg &= ~_BV(INTERRUPT_FLAG_BIT); } #ifdef CAPS_SAVE_CTX __attribute__ ((naked, optimize("-Os"))) #else __attribute__ ((optimize("-Os"))) #endif void dbg_brk() { dbg_enter_debug(); #ifdef CAPS_DISABLE_TIMERS dbg_disable_timers(); #endif #ifdef CAPS_EXECUTE if (dbg_context.ctx_state & _BV(DBG_FLAG_EXECUTING)){ dbg_leave_debug(); asm volatile("ret \n\t"); } else dbg_context.ctx_state |= _BV(DBG_FLAG_EXECUTING); #endif #ifdef CAPS_SINGLE_STEP if (dbg_context.ctx_state & _BV(DBG_SINGLE_STEP_ISR)){ dbg_context.ctx_state &= ~_BV(DBG_SINGLE_STEP_ISR); dbg_disable_single_step(); } #endif ////////////////////////////////////////////////////////////////////////// // Disable the Watchdog dbg_disable_watchdog(); ////////////////////////////////////////////////////////////////////////// // Notify we reached a debug point dbg_send_info(); while(1){ dbg_context.tmp_u8 = dbg_get_ch(); if (dbg_context.tmp_u8 == DEBUG_REQ_CONTINUE){ break; } else if (dbg_context.tmp_u8 == DEBUG_REQ_READ_RAM){ dbg_read_mem_op(); while(dbg_context.mem_op.size.d16--){ dbg_put_ch(*dbg_context.mem_op.buff.ptr++); } } // Everything bellow is optional depending on how big we want the debug code to be // and what functionality we want to / can have #ifdef CAPS_RAM_WRITE else if (dbg_context.tmp_u8 == DEBUG_REQ_WRITE_RAM){ // Normally we should check to see where we are writing to // If we are writing to any SAVED registers // we want to update the saved data and not the live one // however this can be more easily handled in the debug server than on the client // this way the code on the client is small, fast and clean. dbg_read_mem_op(); while(dbg_context.mem_op.size.d16--){ *dbg_context.mem_op.buff.ptr++ = dbg_get_ch(); } } #endif #ifdef CAPS_UART_HIGH_SPEED else if (dbg_context.tmp_u8 == DEBUG_REQ_UART_HIGH_SPEED){ // Save the UART configuration dbg_save_uart_state(); // Initialize debug communication dbg_init_uart(); dbg_context.ctx_state |= _BV(DBG_FLAG_UART_HIGH_SPEED); } #endif #ifdef CAPS_DBG_CTX_ADDR // This is needed in case we don't have the elf file, // and we don't know where the context is located in memory // and what size it has else if (dbg_context.tmp_u8 == DEBUG_REQ_GET_CTX_ADDR){ dbg_put_ch(((uint16_t)&dbg_context) >> 8); dbg_put_ch(((uint16_t)&dbg_context) & 0xFF); uint16_t size = sizeof(dbg_context); dbg_put_ch(size >> 8); dbg_put_ch(size & 0xFF); } #endif #ifdef CAPS_FLASH_READ else if (dbg_context.tmp_u8 == DEBUG_REQ_READ_FLASH){ dbg_read_mem_op(); while(dbg_context.mem_op.size.d16--){ dbg_put_ch(pgm_read_byte(dbg_context.mem_op.buff.addr++)); } } #endif #ifdef CAPS_FLASH_WRITE else if (dbg_context.tmp_u8 == DEBUG_REQ_WRITE_FLASH){ // nothing for now, AVR's only supports write to flash from bootloader // since we are not part of it, we can't write to flash break; } #endif #ifdef CAPS_EEPROM_READ else if (dbg_context.tmp_u8 == DEBUG_REQ_READ_EEPROM){ dbg_read_mem_op(); while(dbg_context.mem_op.size.d16--){ dbg_put_ch(dbg_eeprom_read(dbg_context.mem_op.buff.addr++)); } } #endif #ifdef CAPS_EEPROM_WRITE else if (dbg_context.tmp_u8 == DEBUG_REQ_WRITE_EEPROM){ dbg_read_mem_op(); dbg_eeprom_write(dbg_context.mem_op.buff.addr, dbg_get_ch()); } #endif #ifdef CAPS_SINGLE_STEP else if (dbg_context.tmp_u8 == DEBUG_REQ_SINGLE_STEP){ dbg_enable_single_step(); dbg_context.ctx_state |= _BV(DBG_WILL_SINGLE_STEP); // Exit the read loop and return to caller break; } #endif #ifdef CAPS_EXECUTE else if (dbg_context.tmp_u8 == DEBUG_REQ_EXECUTE){ // Nothing for now, we should call methods from here // TODO: Figure out the how we receive / setup parameters, // and how we are going to send data back after we do the call // Also how do we handle strings sent as parameters, we need to setup a memory region and copy the string there? break; } #endif } #ifdef CAPS_UART_HIGH_SPEED // RESTORE the UART registers if (dbg_context.ctx_state & _BV(DBG_FLAG_UART_HIGH_SPEED)){ dbg_restore_uart_state(); dbg_context.ctx_state &= ~_BV(DBG_FLAG_UART_HIGH_SPEED); } #endif #ifdef CAPS_EXECUTE // Clear execute flag dbg_context.ctx_state &= ~_BV(DBG_FLAG_EXECUTING); #endif // Restore the watchdog register dbg_restore_watchdog(); #ifdef CAPS_SINGLE_STEP if (dbg_context.ctx_state & _BV(DBG_SINGLE_STEP_ISR)){ if (dbg_context.ctx_state & _BV(DBG_WILL_SINGLE_STEP)){ // Do not clear the ISR state just return from the current ISR dbg_context.ctx_state &= ~_BV(DBG_WILL_SINGLE_STEP); }else{ // We will not single step again // clear the flag and return from ISR dbg_context.ctx_state &= ~_BV(DBG_SINGLE_STEP_ISR); } dbg_disable_interrupts(); dbg_leave_debug(); asm volatile ("reti \n\t"); }else if (dbg_context.ctx_state & _BV(DBG_WILL_SINGLE_STEP)){ dbg_context.ctx_state &= ~_BV(DBG_WILL_SINGLE_STEP); dbg_context.ctx_state |= _BV(DBG_SINGLE_STEP_ISR); dbg_disable_interrupts(); dbg_leave_debug(); asm volatile ("reti \n\t"); } #endif // Leave debug and set back the status register // this will re-enable interrupts if needed dbg_leave_debug(); asm volatile ("ret \n\t"); } #ifdef CAPS_SINGLE_STEP ISR ( AVR8_INT_SOURCE, ISR_BLOCK ISR_NAKED ){ asm volatile ("jmp dbg_brk"); } #endif // Used for interrupt handling, instead of a reset we can enter debug and see what happened //__attribute__((used, naked)) //void __vector_default(){ //dbg_brk(); //} #endif /* DEBUG_H_ */ Link to comment
Guest Razvan Marinovici Posted June 29, 2017 Share Posted June 29, 2017 Dupa o pauza destul de lunga (nu am mai apucat sa fac nimic la el), am reinceput. Am facut public codul pe GIT. Este work in progress, asa ca va rog fara prea multe comentarii legat de structura proiectelor. https://github.com/MRazvan/ASAVRSD Sunt 5 proiecte - Codul pentru Arduino - Codul pentru Atmel Studio - Codul pentru o aplicatie consola - Codul pentru o aplicatie stand alone - Codul pentru serverul de debug. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now