Debugging tool for mbed enabled microcontrollers, especially for NUCLEO-F303RE and STM32F042F6P6.

Debug.h

Committer:
bieleluk
Date:
2021-03-21
Revision:
25:cda8a4f9874a
Parent:
24:014f13c3f871

File content as of revision 25:cda8a4f9874a:

#pragma once

// include libraries
//------------------------------------------------------------------------------------------------------------------
#include "mbed.h"
#include <stdlib.h>



// macros
//------------------------------------------------------------------------------------------------------------------
#define name(var)  #var 
#define min(a, b) (((a) < (b)) ? (a) : (b)) 
#define max(a, b) (((a) > (b)) ? (a) : (b)) 


typedef enum
{
   GND = 0,
   BUTTON_GND = 0,
   VDD = 1,
   BUTTON_VDD  = 1,
   VCC = 1,
   BUTTON_VCC  = 1,
} button_mode;

//------------------------------------------------------------------------------------------------------------------
/** Debug_serial class.
 *  Class for stepping the program, printing the curent position of breakpoint and optional print of one variable (int, float, char or char*).
 *  Functions printf, putc and getc are also defined in the class. \n
 *
 * Example program for STM32F042F6P6::
 * @code
 * // ----------------------------------------------------------------------------
 * // Example program of Debug_serial class for STM32F042F6P6
 * // Author: Lukas Bielesch 
 * // Department of Measurement, Czech technical university in Prague, Czech Republic 
 * // Date of publication: 20. March 2021
 * // ----------------------------------------------------------------------------
 * #include "mbed.h"
 * #include "Debug.h"
 * 
 * // two pwm generators based on one timer TIM1
 * PwmOut led1(PA_7);
 * PwmOut led2(PB_1);
 * 
 * // debug serial port on PA_2 and PA_3 with default baudrate of 115200 Bd/s
 * Debug_serial pc(PA_2, PA_3); 
 * 
 * int main(){
 *     
 *     float float_var = 3.14;
 *     int int_var = 42;
 *     char* str_var = "this is string";
 *     
 *     // class Debug_serial works as normal serial port
 *     pc.printf("insert character\n\r");
 *     while (!pc.readable()){}
 *     pc.printf("you have inserted %c\n\r", pc.getc());
 *     
 *     
 *     led1.period(1); // set period of led1 to 1s
 *     led1 = 0.6; // set stride of led1 to 60% 
 *     
 *     // breakpoint with 3 parameters: line of the breakpoint, name and value of the variable to be shown
 *     pc.breakpoint(__LINE__, name(float_var), float_var);
 *     
 *     // period of both LEDs is changed to 0.5s
 *     led2.period(0.5);
 *     
 *     pc.breakpoint(__LINE__, name(int_var), int_var);
 *     
 *     // set stride of led2 to 40%
 *     led2 = 0.4;
 *     
 *     pc.breakpoint(__LINE__, name(str_var), str_var);
 *     
 *     // period of both LEDs is changed to 2s 
 *     led2.period(2);
 *     
 *     // breakpoint with 2 parameters: line of the breakpoint and address of 4-byte word to be read
 *     pc.breakpoint(__LINE__, 0x48000000);
 *     
 *     
 *     pc.printf("end of program\n\r");
 *         
 *     while(1){}
 *     
 * }
 * @endcode
 */
class Debug_serial {
public:

    /** Create object of Debug_serial class.
     * @param tx_pin TX pin of debug serial port
     * @param rx_pin RX pin of debug serial port
     * @param baudrate(optional) desired baudrate value of debug serial port, default baudrate is 115200 Bd/s
     */
    Debug_serial(PinName tx_pin, PinName rx_pin, int baudrate = 115200);
    
    /** Perform one breakpoint.
     * @param line_number (optional) line number of breakpoint, macro __LINE__ could be used.
     */ 
    void breakpoint(int line_number = -1);

    /** Perform one breakpoint and print variable of type int
     * @param line_number line number of breakpoint, macro __LINE__ could be used.
     * @param name name of printed variable(max length is 19) , macro name(variable) could be used.
     * @param variable variable of type int
     */     
    void breakpoint(int line_number, char name[20], int variable);
    
    /** Perform one breakpoint and print variable of type char
     * @param line_number line number of breakpoint, macro __LINE__ could be used.
     * @param name name of printed variable(max length is 19) , macro name(variable) could be used.
     * @param variable variable of type int
     */     
    void breakpoint(int line_number, char name[20], char variable);
    
    /** Perform one breakpoint and print string variable
     * @param line_number line number of breakpoint, macro __LINE__ could be used.
     * @param name name of printed variable(max length is 19) , macro name(variable) could be used.
     * @param variable variable of type char*
     */     
    void breakpoint(int line_number, char name[20], char * variable);
    
    /** Perform one breakpoint and print variable of type float
     * @param line_number line number of breakpoint, macro __LINE__ could be used.
     * @param name name of printed variable(max length is 19) , macro name(variable) could be used.
     * @param variable variable of type float
     */ 
    void breakpoint(int line_number, char name[20], float variable);
    
    /** Perform one breakpoint and print one register value
     * @param line_number line number of breakpoint, macro __LINE__ could be used.
     * @param address address of register, must be divisible by 4 or it will be floored to value divisible by 4.
     */ 
    void breakpoint(int line_number, uint32_t address);
    
   /** Print formatted string to debug serial port
     * @returns total number of printed characters or negative value if an output error or an encoding error
     */
    int printf(const char* format, ...);

   /** Read formatted string from debug serial port
     * @returns total number of successfully read arguments or negative value if en error occured
     */   
    int scanf(const char* format, ...);
    
    /** Print one character to debug serial port 
     * @param character
     * @returns character written as an unsigned char cast to an int
     */
    int putc(int character);
    
    /** Read one character from debug serial port 
    * @returns character written as an unsigned char cast to an int
    */
    int getc();
    
    /** Check whether there is some character available to read from debug serial port.
    * @returns true when there is something available to read
    */    
    bool readable();
    
    /** Check whether it is possible to write a character to debug serial port.
    * @returns true when it is possible to write a character to debug serial port
    */ 
    bool writable();
    
private:
    int break_line[3]; //store number of lines of three previous breakpoints
    char var[3][50]; //store variables of three previous breakpoints
  
protected:  
// objects:
    Serial pc; //debug serial port
// variables
    int breakpoint_count; //stores number of the current breakpoint
// functions
    // initialization function    
    void init();
    // print 3 last breakpoints
    void print_3_breaks(int line_number);
    // print one breakpoint
    void print_one_break(int n);
    // clear screen from m line up to n line
    void clear_from_n_up_to_m(int m, int n);
};

//------------------------------------------------------------------------------------------------------------------

/** Debug_led class.
 *  Class for stepping the program with debug LED and button, that is connected to GND(default) or VCC. External pull up/down resistor does not have to be used.\n
 *  Example program for STM32F042F6P6:
 * @code
 * // ----------------------------------------------------------------------------
 * // Example program of Debug_led class for STM32F042F6P6
 * // Author: Lukas Bielesch 
 * // Department of Measurement, Czech technical university in Prague, Czech Republic 
 * // Date of publication: 20. March 2021
 * // ----------------------------------------------------------------------------
 * #include "mbed.h"
 * #include "Debug.h"
 * 
 * PwmOut pwm(PA_4); 
 * DigitalOut led(PA_1);
 * Debug_led deb(PA_5, PA_7, GND); //debug led on PA_5, debug button connected to ground on PA_7
 * 
 * int main(){
 * 
 *     led = 1;
 *     deb.breakpoint(); // breakpoint with periodical flashing with 300 ms period until the button is pressed
 *     pwm = 0.5;
 *     pwm.period(1);
 *     deb.breakpoint(2, 200); // breakpoint with periodical double-flashing with 200 ms period   
 * 
 *     while(1){
 *         deb.breakpoint(3); // breakpoint with periodical triple-flashing until the button is pressed
 *         pwm = pwm + 0.1f;
 *         
 *         //init pwm on the pin without pwm functionality causes MbedOS Error
 *         // error message is sent to uart on PA_2 and PA_3
 *         PwmOut pwm2(PA_0); 
 *         
 *         wait(2);
 *     }
 * }
 *
 * @endcode
 */
// class Debug_led
class Debug_led {
public:

    /** Create an object of Debug_led class
     * @param led_pin pin of of debug led
     * @param button_pin pin of of debug button
     * @param mode mode of button connection(GND/VCC), default value value is GND
     */
    Debug_led(PinName led_pin, PinName button_pin, button_mode mode = GND);
    
    /** Perform one breakpoint. 
     * At first, the program waits until the the button is released (from the previous breakpoint). 
     * Then it periodically flashes for number times with period of period_ms ms until the button is pressed,
     * @param number number of flashes of LED during the breakpoint, default value is 1
     * @param period_ms period of flashing of the LED in ms, default value is 300ms
     */
    void breakpoint(int number = 1, int period_ms = 300);

private:  
// objects
    DigitalOut led; //debug led
    InterruptIn button; //debug button
// variables
    int b_mode; // mode of button connection(GND = 0, VCC = 1)
    volatile bool end_breakpoint; //true when button was pushed
//    int number_of_breakpoints; //number of the current breakpoint
    
    /** Initialization */
    void init(button_mode mode);
    
    /** Blink the debug led n-times with blink period  wait_time_ms */
    void flash_n_times(int wait_time_ms, int n);
    
    /** IRQ handler function, end breakpoint after the button is pushed */
    void end_break();
};

//------------------------------------------------------------------------------------------------------------------
/** Debug_register class.
 *
 * Example program:
 * @code
 * // ----------------------------------------------------------------------------
 * // Author: Lukas Bielesch 
 * // Department of Measurement, Czech technical university in Prague, Czech Republic 
 * // Date of publication: 15. Apr 2019
 * // ----------------------------------------------------------------------------
 * #include "Debug.h"
 * AnalogIn analog(PA_4);
 * PwmOut pwm(PA_6);
 * DigitalOut out(PA_5);
 * Debug_register pc(PA_2, PA_3, 115200);
 *  
 * int main(){
 *     pc.breakpoint(__LINE__,0x48000000);
 *     DigitalOut out2 (PA_0);
 *     pc.breakpoint(__LINE__,0x48000001);
 *     AnalogIn analog2 (PA_1);
 *     pc.breakpoint(__LINE__,0x4800000C);
 *     DigitalIn di1(PA_7, PullUp);
 *     pc.breakpoint(__LINE__,0x4800000C);
 *     pc.breakpoint(__LINE__,0x48000004);
 *     while(1){
 *         if(pc.readable()){
 *             pc.putc(pc.getc());
 *         }
 *         wait(0.1);
 *     }
 * }
 * @endcode
 */
class Debug_register {
public:

    /** Create object of Debug_register class
     * @param tx_pin TX pin of debug serial port
     * @param rx_pin RX pin of debug serial port
     * @param baudrate(optional) desired baudrate value of debug serial port, default baudrate is 115200 Bd/s
     */
    Debug_register(PinName tx_pin, PinName rx_pin, int baudrate = 115200);
    
    /** Perform one breakpoint and print one register
     * @param line_number line number of breakpoint, macro __LINE__ is recommended
     * @param address address of register, must be divisible by 4
     */ 
    void breakpoint(int line_number, uint32_t address);

   /** Print formatted string to debug serial port
     * @returns total number of printed characters or negative value if an output error or an encoding error
     */
    int printf(const char* format, ...);

   /** Read formatted string from debug serial port
     * @returns total number of successfully read arguments or negative value if en error occured
     */   
    int scanf(const char* format, ...);
    
    /** Print one character to debug serial port 
     * @param character
     * @returns character written as an unsigned char cast to an int
     */
    int putc(int character);
    
    /** Read one character from debug serial port 
    * @returns character written as an unsigned char cast to an int
    */
    int getc();
    
    /** Check whether there is some character available to read from debug serial port.
    * @returns true when there is something available to read
    */    
    bool readable();
    
    /** Check whether it is possible to write a character to debug serial port.
    * @returns true when it is possible to write a character to debug serial port
    */ 
    bool writable();
  
protected:  
// objects:
    Serial pc; //debug serial device
// variables:
    int breakpoint_count; //number of the current breakpoint
// functions
    // initialization function    
    void init();
    // clear screen from m line up to n line
    void clear_from_n_up_to_m(int m, int n);
    // modify actual address or register value according to position in terminal
    uint32_t modify_value(uint32_t value, int horizontal);
    // print address and register value
    void print_break(uint32_t address);
    // print number in binary form
    void print_binary(uint32_t value);
};

////------------------------------------------------------------------------------------------------------------------
///** Debug_register_print class.
// *
// * Example program:
// * @code
// * // ----------------------------------------------------------------------------
// * // Author: Lukas Bielesch 
// * // Department of Measurement, Czech technical university in Prague, Czech Republic 
// * // Date of publication: 15. Apr 2019
// * // ----------------------------------------------------------------------------
// * #include "Debug.h"
// * AnalogIn analog(PA_4);
// * PwmOut pwm(PA_6);
// * DigitalOut out(PA_5);
// * Debug_register_print pc(PA_2, PA_3, 115200);
// *  
// * int main(){
// *     pc.format(2,2,1,3);//breakpoint count,line number, address, value
// *     pc.breakpoint(__LINE__,0x48000001, 2);
// *     DigitalOut out2 (PA_0);
// *     pc.breakpoint(__LINE__,0x48000014, -3);
// *     AnalogIn analog2 (PA_1);
// *     pc.breakpoint(__LINE__,0x48000008);
// * 
// *     while(1){
// *         wait(1);
// *     }
// * }
// * @endcode
// */
class Debug_register_print {
public:

//    /** Create object of Debug_register_print class
//     * @param tx_pin TX pin of debug serial port
//     * @param rx_pin RX pin of debug serial port
//     * @param baudrate(optional) desired baudrate value of debug serial port, default baudrate is 115200 Bd/s
//     */
    Debug_register_print(PinName tx_pin, PinName rx_pin, int baudrate = 115200);

//    /** Set format of breakpoint message
//     * @param break_number format of number of actual breakpoint: 0->not show, 1->show in hexadecimal, 2->show in decimal(default)
//     * @param line format of line of actual breakpoint: 0->not show, 1->show in hexadecimal, 2->show in decimal(default)
//     * @param address format of address of register: 0->not show, 1->show in hexadecimal(default), 2->show in decimal
//     * @param value format of register value: 0->not show, 1->show in hexadecimal, 2->show in decimal, 3->show in binary(default)
//     */
    void format(int break_number = 2, int line = 2, int address = 1, int value = 3);
    
//    /** Perform one breakpoint and print one register value
//     * @param line_number line number of breakpoint, macro __LINE__ is recommended
//     * @param address address of register , must be divisible by 4
//     */ 
    void breakpoint(int line_number, uint32_t address, int number_of_words = 1);

  
protected:  
// objects:
    Serial pc; //debug serial device
// variables:
    int breakpoint_count; //number of the current breakpoint
    int count_format; // format of breakpoint count, 0->not show, 1->show in hexadecimal, 2->show in decimal
    int line_format; // format of lineof breakpoint, 0->not show, 1->show in hexadecimal, 2->show in decimal
    int address_format; // format of address of register, 0->not show, 1->show in hexadecimal, 2->show in decimal
    int register_format;// format of register value, 0->not show, 1->show in hexadecimal, 2->show in decimal, 3->show in binary
// functions
    // initialization function    
    void init();

};