Close
0%
0%

Electronic Load 3.3V-16V 1A

Electronic load that supports 3.3V-16V at 1A of current. Equipped with keypad, LCD, rotary encoder, STM32 Microcontroller and more!

Similar projects worth following
Electronic load that supports 3.3V-16V at 1A of current. My goal was to develop a useful tool for my bench, while learning many aspect of electronics engineering. I could have made a simple electronic load, but I also wanted to create a useful development environment for the STM32 micro-controller family. I have not used the STM32 micro-controller family before, and would like to take advantage of its powerful capabilities, while branching away from the typical Arduino environment I have become comfortable with. Some of the features include a DAC (Digital to Analog Converter), custom keypad, rotary encoder, LCD module, voltage measurements, current measurements, temperature measurements, buzzer, USB to Serial interface & RGB LED.

I will be adding project details once I have the project a bit more finalized.  I plan on adding very detailed descriptions for each circuit, but would like to avoid re-doing a bunch of stuff if changes are required.

Please follow project logs in short term for project related details.  I plan on providing updates after completion of major milestones.

x-zip-compressed - 211.36 kB - 12/01/2019 at 19:27

Download

Adobe Portable Document Format - 268.95 kB - 12/01/2019 at 19:27

Preview
Download

OpenDocument Spreadsheet - 23.82 kB - 12/01/2019 at 19:27

Download

  • 1 × See Attached BOM See Attached BOM

  • Key Pad Loop Times

    schwarzrmsu01/16/2020 at 23:57 0 comments

    In my previous project log I developed a function to read the key pad.  In this function there were some necessary delays in order to allow the digital output to fully charge the capacitor on the digital input filter before checking the digital input status (check out more details on the keypad in my previous project log).  This delay is based on the RC time constant of the RC low pass filter I have placed in front of each digital input for the key pad.

    Below is a visual example of whats happening in the circuit:

    You can see that the signal at TP7 and TP23 are instantaneous because there is no deliberate capacitance tied to that node.  Therefore the rise and fall times are going to be "instantaneous".  The problem is the signal at the digital input is not "instantaneous" because of the resistance/capacitance combination.  This resistance/capacitance combination is called a passive low pass filter.  Its a cheap and effective way of filtering out unintended high frequencies that you do not want present at your digital input.  These high frequencies can come from a number of sources, but typically it is outside RF being coupled into the trace acting like an antenna.

    In order to use this low pass filter, we need to wait for the signal to catch up before we read it.  This time is based off the RC time constant of the low pass filter.  The RC time constant formula is below:

    For our circuit we have to consider R as the two 10k resistors, and C as the 0.01uF capacitor.  It is best practice to use the worst case value when running an analysis to ensure its compatible across all possible conditions.  For this scenario the worst case condition is at the maximum resistance & capacitance values.  Our maximum component values are calculated below:

    Unfortunately 1T is not enough time since that will only allow the voltage to reach 63% of the steady state value.  Its best to wait at least 5T in order for the capacitor in the low pass filter to fully charge before reading the input.  This is shown best in the figures below:

    Therefore the delay we need to wait after each row is powered is calculated below:

    I rounded this value up to an even 1200us and tested the response:

    Here you can see the Digital Ouput Voltage (CH1) is instantaneous and the voltage at the Digital Input (CH2) has reached its steady state.  This is exactly what you want to see in order to ensure the voltage you we monitoring has reached its steady state.

    The problem is this takes place 4 times during the readKeyPad() function which gives us a worst case function delay of  ~4.8ms.  I measured this by executing the following code and taking a measurement on the green LED control:

         if (mainMillis - readKeyPadMillis >= 10)
          {
              turnOnGreenLED();
              readKeyPad();
              turnOffGreenLED();
              readKeyPadMillis = mainMillis;
          }
    

    This function will set the green LED control high, run the readKeyPad() function, and then set the green LED control low.  I did this an probed the green LED control to measure the time it takes to execute this function:

    As you can see, it takes 4.81ms to execute the readKeyPad() function.  This is too long in my opinion, therefore we need to make some HW changes in order to reduce the delays required for this feature.  We either need to reduce the low pass filter resistance or capacitance in order to reduce the RC time constant which directly correlates to the required delay.  This will move the corner frequency of our low pass filter, but this trade off is definitely worth it.  I decided to keep the resistance the same, but to replace the 0.01uF capacitors with 0.001uF capacitors:  

    First we had to find C14, C15, C16 & C17 on the PCBA:

    Remove these capacitors from the PCBA:

    Solder 0.001uF capacitors:

    Below is a waveform with the same delay but new capacitors:

    ... Read more »

  • Key Pad Fun Times

    schwarzrmsu01/16/2020 at 03:40 0 comments

    Now that I have figured out digital outputs & delays, the next logical step would be to play with those new features while introducing digital inputs as well.  A portion of the design that requires digital output controls, reading digital inputs and delays is the key pad.  In order to understand the keypad software, I will give an explanation of the keypad hardware.

    The key pad consists of 16 push buttons:

    Schematic View:

    PCBA View:

    The simplest approach would be to tie all 16 push buttons to a voltage source (3.3V) and route the normally open end of each push button to a discrete digital input.  The problem with this approach is it would require 16 GPIO pins on the micro which is a lot for one feature.  In order to minimize the required number of GPIO, I used a multiplexed approach which only requires 8 GPIO.

    The best way to explain the multiplexed approach is to go through an example.  I will show you how the micro-controller will determine that the 9 key (push button 11) is being pushed.  

    The micro-controller is going to individually power each row, one at a time using digital outputs I named KEY_PAD_R1, KEY_PAD_R2, KEY_PAD_R3 & KEY_PAD_R4.  While each row is getting powered individually, the micro-controller is going to check each column one at time using digital inputs I named KEY_PAD_C1, KEY_PAD_C2, KEY_PAD_C3 & KEY_PAD_C4.

    When KEY_PAD_R1 digital output is high, this is what the micro-controller will see when the 9 key is pushed:

    You can see all digital inputs are reading 0V which is an indication that the 1, 2, 3 or ESC keys are not being pushed.

    When KEY_PAD_R2 digital output is high, this is what the micro-controller will see when the 9 key is pushed:

    You can see all digital inputs are reading 0V which is an indication that the 4, 5, 6 or 0 keys are not being pushed.

    When KEY_PAD_R3 digital output is high, this is what the micro-controller will see when the 9 key is pushed:

    You can see in this scenario, the KEY_PAD_C3 digital input is reading 3.3V.  The micro will have the 9 key mapped to this condition of KEY_PAD_R3 digital output high & KEY_PAD_C3 digital input high.  In fact all keys will have a unique combination that will allow to the micro-controller discretely identify when each key is being pressed.

    Lastly when KEY_PAD_R4 digital output is high, this is what the micro-controller will see when the 9 key is pushed:

    You can see all digital inputs are reading 0V which is an indication that the ISET, ENTER, NULL or ON/OFF keys are not being pushed.

    The logic in the micro-controller can be mapped to this table:

    KEY_PAD_R1 Digital Ouput High & KEY_PAD_C1 Digital Input High = 1 Key is pressed

    KEY_PAD_R1 Digital Ouput High & KEY_PAD_C2 Digital Input High = 2 Key is pressed

    KEY_PAD_R1 Digital Ouput High & KEY_PAD_C3 Digital Input High = 3 Key is pressed

    KEY_PAD_R1 Digital Ouput High & KEY_PAD_C4 Digital Input High = ESC Key is pressed

    KEY_PAD_R2 Digital Ouput High & KEY_PAD_C1 Digital Input High = 4 Key is pressed

    KEY_PAD_R2 Digital Ouput High & KEY_PAD_C2 Digital Input High = 5 Key is pressed

    KEY_PAD_R2 Digital Ouput High & KEY_PAD_C3 Digital Input High = 6 Key is pressed

    KEY_PAD_R2 Digital Ouput High & KEY_PAD_C4 Digital Input High = 0 Key is pressed

    KEY_PAD_R3 Digital Ouput High & KEY_PAD_C1 Digital Input High = 7 Key is pressed

    KEY_PAD_R3 Digital Ouput High & KEY_PAD_C2 Digital Input High = 8 Key is pressed

    KEY_PAD_R3 Digital Ouput High & KEY_PAD_C3 Digital Input High = 9 Key is pressed

    KEY_PAD_R3 Digital Ouput High & KEY_PAD_C4 Digital Input High = . Key is pressed

    KEY_PAD_R4 Digital Ouput High & KEY_PAD_C1 Digital Input High = ISET Key is pressed

    KEY_PAD_R4 Digital Ouput High & KEY_PAD_C2 Digital Input High = ENTER Key is pressed

    KEY_PAD_R4 Digital Ouput High & KEY_PAD_C3 Digital Input High = NULL Key is pressed

    KEY_PAD_R4 Digital Ouput High & KEY_PAD_C4 Digital Input High = ON/OFF...

    Read more »

  • Millis Function

    schwarzrmsu01/13/2020 at 02:38 0 comments

    In order to avoid large pockets of delay, I will need to generate a function that will allow me to execute specific actions only after a certain amount of time has expired.  In arduino, this can be accomplished using the millis() function.  Since I am using the STM32 micro-controller and the STM32 IDE, I do not have the luxury of using this library function.  Therefore I have created my own millis function.  Probably not as good, but seems to be working pretty well. 

    The first step was to enable a new timer that counts up at a rate of 100kHz (In other words it counts to 100 every 1ms):

    static void MX_TIM7_Init(void)
    {
      htim7.Instance = TIM7;
      htim7.Init.Prescaler = 479; //479
      htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim7.Init.Period = 65535;
      htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
      {
        Error_Handler();
      }
    }

    This function configures a timer to count up to 100 every 1ms.  The reason I have slowed down this timer is to prevent the 16 bit unsigned integer from over flowing too quickly.  This timer can overflow after following duration:

    Once all of my code is complete, I can start to bench mark the amount of time it takes to execute the entire stack.  With that information I can fine tune my timer frequency, but for now I will conservatively set the frequency to 100kHz.

    Now that I have a timer that counts to 100 every 1ms, I have created a function that counts how many times this happens:

    uint32_t millis(void)
    {
        uint16_t CURRENT_TIMER7_COUNT = __HAL_TIM_GET_COUNTER(&htim7);
    
        uint16_t currentMillis = 0;
        if(CURRENT_TIMER7_COUNT>=100)
        {
            currentMillis = CURRENT_TIMER7_COUNT/100;
            systemMillis = systemMillis + currentMillis;
            __HAL_TIM_SET_COUNTER (&htim7, 0);
        }
        return systemMillis;
    }

    This function checks the current count at the time this function is called.  If the count is larger than 100 it increases a variable called systemMillis by 1.  systemMillis is the current number of milliseconds the application has been running.  If the counter is increased it resets the counter to prevent it from overflowing.  systemMillis is a 32 bit unsigned integer which will take a long time to over flow.  The systemMillis variable will overflow after this specified amount of time:

    This is an acceptable amount of time to run this particular application with requiring a reset.  Once this timer expires I plan on resetting all the Millis related variables which might cause a slight timing mishap, but should not be noticeable to the user if the user has left application running longer than 49.71 days.

    I then tested this function within main while(1) by blinking an LED on and off and probing the LED DO port:

    mainMillis = millis();
    
    if (mainMillis - turnOnRedLedMillis >= 1000)
    {
        HAL_GPIO_TogglePin(DEBUG_RGB_LED_R_DO_PORT, DEBUG_RGB_LED_R_DO_PIN);
        turnOnRedLedMillis = mainMillis;
    }

     1s:

    100ms:

    10ms:

    5ms:

    1ms:

    These results are adequate for my needs.  This new function will help me execute portions of the code only when they really need to be execute.  I think this will be most useful for low priority portions of the code being executed less then portions that are higher priority.

    There are many uses for this function and you will be sure to see it future updates regarding SW.

    Hope you found this interesting, and if you have any ideas that would work better please let me know.  Thank you for reading.

  • Programming Header Simplification

    schwarzrmsu12/21/2019 at 04:53 0 comments

    I have been getting annoyed with my current programming header connections:

    The connections need to be individually un-done and re-done if you want to disconnect the programming tool from the PCB. Therefor i have decided to make an adapter board that would make my programming interface directly compatible with the main 14 pin header on the STLINK-V3:

    Image result for st link v3

    Below is the schematic I created:

    Below is the board I designed:

    I ordered these boards on OSH Park, and took advantage of the cool "After Dark" option that is currently available:

    This board construction is really cool because it uses a dark substrate and a clear soldermask.  This makes it look like the copper is exposed, but it is in fact under a layer of clear solder resist material.

    The construction on these boards is really incredible.  The copper etching and silk screen definition is insanely good.

    I then soldered the connector to the board, and this jumper board to my PCB:

    I then connected to the STLINK-V3 using the 14 way ribbon cable as mentioned earlier:

    After a quick test, I was able to connect to my micro-controller and successfully flash the micro-controller.  This makes disconnecting and reconnecting the STLINK-V3 much easier.  This also cleans up my bench setup as well.

    Hope you found this interesting.  Thanks for reading.

  • Hello World - LCD Edition

    schwarzrmsu12/19/2019 at 02:57 0 comments

    The LCD when powered looks so cool, lets make it say something now!  

    This has definitely been the hardest part yet, and will most likely be a work in progress as the SW matures.  Later versions are going to take a number of inputs and map them onto the display to show information related to the electronic load performance.  For now I simply want to create a function that will print a string onto the LCD.  I started by generating functions to initialize the LCD functionality:

    void LCD_functionSet(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);    //RS
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);    //RW
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);    //DB7
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);    //DB6
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);        //DB5
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);        //DB4
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);        //DB3
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);    //DB2
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);    //DB1
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);    //DB0
    
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);    //E
        delay_us(1);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);    //E
        delay_us(40);
        return;
    }
    
    void LCD_displayOnOffControl(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);    //RS
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);    //RW
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);    //DB7
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);    //DB6
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);    //DB5
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);    //DB4
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);        //DB3
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);        //DB2
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);    //DB1
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);    //DB0
    
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);    //E
        delay_us(1);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);    //E
        delay_us(40);
        return;
    }
    
    void LCD_clearDisplay(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);    //RS
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);    //RW
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);    //DB7
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);    //DB6
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);    //DB5
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);    //DB4
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);    //DB3
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);    //DB2
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);    //DB1
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);    //DB0
    
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);    //E
        delay_us(1);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);    //E
        delay_ms(2);
        return;
    }
    
    void LCD_entryModeSet(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);    //RS
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);    //RW
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);    //DB7
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);    //DB6
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);    //DB5
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);    //DB4
    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);    //DB3
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);        //DB2
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);        //DB1
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);    //DB0
    
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_SET);    //E
        delay_us(1);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET);    //E
        delay_us(40);
        return;
    }

    Now that I have initialized the LCD, I can send commands for the different characters and it will print the characters onto:

    I started with a function to print the letter A:

    void LCD_print_A(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);    //RS
     HAL_GPIO_WritePin(GPIOC,...
    Read more »

  • Hello World - UART Edition

    schwarzrmsu12/19/2019 at 02:04 2 comments

    The next goal for me is to get my UART running.  This will be a huge accomplishment since using a serial monitor is going to be very helpful when debugging code.  I found two really helpful functions online which allow you to pass a character array (char) and it will send the string via the defined UART interface:

    void UART_printString(UART_HandleTypeDef *huart, char _out[])
    {
        HAL_UART_Transmit(huart, (uint8_t *) _out, strlen(_out), 10);
    }
    
    void UART_printlnString(UART_HandleTypeDef *huart, char _out[])
    {
        HAL_UART_Transmit(huart, (uint8_t *) _out, strlen(_out), 10);
        char newline[2] = "\r\n";
        HAL_UART_Transmit(huart, (uint8_t *) newline, 2, 10);
    }

    I plugged in my USB connection and passed a simple "Hello World" string into the UART_printlnString() function:

    UART_printlnString(&huart2,"Hello World");
    delay_ms(1000);

    Unfortunately this did not work right away.  Through some quick trouble shooting, I noticed the USB VBUS fuse F3 had blown open:

    I knew this to be the case because I could measure 5V at J70 when connected to my computer, but J72 was reading ~0V.  After some head scratching, I looked into the details of my USB ESD protection U9 a bit further.  What I noticed is my silk screen did not have any pin 1 identification, and this device definitely needs to be oriented correctly when soldered:

    After some further investigation, I did in fact solder D9 backwards which results in a forward biased diode directly from VBUS to ground through fuse F3.  I corrected the issue by simply removing D9 for now, and replacing F3 with a new fuse.  (I will be fixing the silkscreen in future revisions of the PCB)

    After this change I got the re-assuring ba-da-da-boo from my PC that it recognized a USB device was plugged in.  

    I opened my serial monitor and wah lah:

  • Delays

    schwarzrmsu12/13/2019 at 00:45 0 comments

    One of the first things I do in a SW project is identify the delay functions I wish to use, and test them.  I have not used and STM32 mico before, therefore I am going to test the performance of the HAL_Delay() function:

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
    HAL_Delay(1000);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
    HAL_Delay(1000);

    I measured each delay pulse width using a scope at 1s, 100ms, 10ms, 5ms & 1ms.

    1s:

    100ms:

    10ms:

    5ms:

    1ms:

    At longer delays >100ms I really like the HAL_Delay() function.  At lower delays <10ms I noticed there is nearly a +1ms error that may add a significant amount of overall delay if used often.  Also there is no option to go into a microsecond time frame which will definitely be necessary when writing functions for the LCD.  When driving the LCD, every character write requires a 40us delay, but if using the HAL_Delay(1), it would cause the following overall delay:

    This is a lot of delay for one type of feature, therefore I generated a micro second delay using an internal timer:

    void delay_us(uint16_t delay){
        delay = delay * 48;
        __HAL_TIM_SET_COUNTER (&htim6, 0);
        while (__HAL_TIM_GET_COUNTER(&htim6) < delay);
    }

    This function takes an integer (number of microseconds) multiplies it by 48.  Then it resets timer 6, and timer 6 starts counting up at 48MHz.  Therefore the timer counts to 48 in 1us.  The while loop waits until it counts all the way up to the limit and then returns back to where the function was called.  I made the same measurements on my delay_us() function.

    100us:

    10us:

    5us:

    1us:

    I am really happy with the delay_us() function.  Also I created a delay_ms function:

    void delay_ms(uint16_t delay){
        while(delay > 0){
            delay_us(1000);
            delay = delay - 1;
        }
    }

    This function simply takes an integer, and runs through delay_us(1000) that number of times.  Pretty simple.  Below are the measurements results:

    1s:

    100ms:

    10ms:

    5ms:

    1ms:

    I am very happy with the accuracy of the delay_ms() function as well.  I can be confident how long certain delays should be now that I understand and have measured these delays.

  • Getting To Blinky

    schwarzrmsu12/12/2019 at 01:23 0 comments

    Now that I have connected successfully to the microcontroller, the logical next step is to blink an LED.  I simply plan to test the functionality of the Debug RGB LED by writing some code to turn on and off each element of the RGB LED:

    Microcontroller Pins:

    Debug RGB LED:

    I wrote functions for each LED for Turn On and Turn Off.  I included Red, Green, Blue and all other color combinations.  This will make it easier to toggle these LED's once the code gets more complicated:

    void TurnOnRedLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
        return;
    }
    
    void TurnOffRedLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
        return;
    }
    
    void TurnOnGreenLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
        return;
    }
    
    void TurnOffGreenLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
        return;
    }
    
    void TurnOnBlueLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);
        return;
    }
    
    void TurnOffBlueLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
        return;
    }
    
    void TurnOnYellowLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
        return;
    }
    
    void TurnOffYellowLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
        return;
    }
    
    void TurnOnPurpleLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);
        return;
    }
    
    void TurnOffPurpleLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
        return;
    }
    
    void TurnOnCyanLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);
        return;
    }
    
    void TurnOffCyanLED(void)
    {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
        return;
    }

     I added some simple code in the main while loops to test each function:

      while (1)
      {
          TurnOnRedLED();
          HAL_Delay(1000);
          TurnOffRedLED();
          HAL_Delay(1000);
    
          TurnOnGreenLED();
          HAL_Delay(1000);
          TurnOffGreenLED();
          HAL_Delay(1000);
    
          TurnOnBlueLED();
          HAL_Delay(1000);
          TurnOffBlueLED();
          HAL_Delay(1000);
    
          TurnOnYellowLED();
          HAL_Delay(1000);
          TurnOffYellowLED();
          HAL_Delay(1000);
    
          TurnOnPurpleLED();
          HAL_Delay(1000);
          TurnOffPurpleLED();
          HAL_Delay(1000);
    
          TurnOnCyanLED();
          HAL_Delay(1000);
          TurnOffCyanLED();
          HAL_Delay(1000);
      }

    I then compiled and loaded this code to the micro and tested the SW:

    Red:

    Green:

    Blue:

    Yellow:

    Purple:

    Cyan:

  • Getting To Ready To Code

    schwarzrmsu12/12/2019 at 00:34 0 comments

    Getting started with the software portion of the project proved to be quite difficult.  I had to learn which tools and software to use in order to do so.  Below is a breakdown of my selections along with how you can get started yourself if you wish to use a similar tool chain.

    Programming Tool:

    I chose the STLINK-V3

    https://www.st.com/en/development-tools/stlink-v3set.html

    This seems to be a very versitile tool.  I plan on using the following pins to interface with my board:

    1. VCC (3.3V)
    2. CLK
    3. GND
    4. DIO
    5. NRST (Forgot to route, going to need to solder wire to make connection [TP 47])

    Choosing an IDE:

    Choosing an IDE seemed to be the most difficult decision.  Through a bit of research I decided on using the following tools:

    Powering Board:

    I simply plugged in a 12V center positive plug pack into the power connector.  You could power up using a current limited supply just in case, but I felt confident so I plugged directly into wall.

    You should see the back light on LCD power on:

    You should also be able to measure 3.3V on the voltage regulator:

    Connecting Board To Programming Tool:

    Next I connected the programming tool to my board.  You will need to make the following connections:

    1. VCC (3.3V)
    2. CLK
    3. GND
    4. DIO
    5. NRST (Forgot to route, going to need to solder wire to make connection [TP47])

    I plan on switching to the STLINK-V3 main 14 way connector for future revisions in order to simplify the programming tool connections.

    Communicating With Microcontroller:

    With everything plugged in.  I opened the STM32CubeProgrammer, crossed my fingers and hit connect:

    I succesfully connected to the microcontroller which means I am ready to start programming.

  • Electronic Load 3.3V-16V 1A EDU 1 Release

    schwarzrmsu12/01/2019 at 19:30 0 comments

    Uploaded Electronic Load 3.3V-16V 1A EDU 1 files and updated all relevant material to reflect this latest revision.

View all 10 project logs

  • 1
    Order PCB (Printed Circuit Board)

    The PCB is a custom designed component, therefore you will need to order this part from PCB manufacturers like https://oshpark.com/ or https://jlcpcb.com/.  The gerbers I have attached to this project are very conservatively designed in order to be directly compatible with these services.  You should be able to simply drop the zip file into the website and select the necessary settings.

    From JLPCB:

    Track the production progress and shipping until the boards arrive:

  • 2
    Order All Electrical & Mechanical Components

    The rest of the BOM items are off the shelf devices, therefore you can purchase these from a number of sources like https://www.digikey.com/ or https://www.mouser.com/.  The BOM I have attached to this project show Manufacturer, Manufacturer PN & Quantity:

    Quantity Description Manufacturer
    1 AUDIO PIEZO TRANSDUCER 12.5V SMD Murata Electronics North America
    1 CAP SMD CER 0.1UF 50V 10% X7R 0603 FLEXSAFE AVX Corporation
    1 CAP SMD CER 10UF 25V 10% X7R 1210 FLEXSAFE AVX Corporation
    15 CAP SMD CER 0.01UF 50V 10% X7R 0603 Samsung Electro-Mechanics
    1 CAP SMD AEC 10UF 35V 20% 105 Wurth Electronics Inc.
    12 CAP SMD CER 0.1UF 50V 10% X7R 0603 Yageo
    2 CAP SMD CER 47pF 50V 5% C0G/NP0 0603 Walsin Technology Corporation
    1 CAP SMD CER 4.7UF 25V 10% X5R 0805 Samsung Electro-Mechanics
    5 CAP SMD CER ESD 0.01UF 100V 10% X7R 0603 KEMET
    2 TVS DIODE 33V SMB Littelfuse Inc.
    1 DIODE SCHOTTKY 40V 1A SOD123 Diodes Incorporated
    2 TVS DIODE 3.3V SOD923 ON Semiconductor
    1 LED RGB 622NM 530NM 470NM 6SMD CREE Inc.
    1 LED GREEN CLEAR 0603 SMD Lite-On Inc.
    1 LED BLUE CLEAR 0603 SMD Lite-On Inc.
    1 DIODE ZENER 17V 500MW SOD123 ON Semiconductor
    1 FUSE 500MA 125VAC FAST 1206 Bel Fuse Inc.
    1 FUSE 2A 125VAC FAST 1206 Bel Fuse Inc.
    1 FUSE 250MA 125VAC FAST 1206 Bel Fuse Inc.
    1 FERRITE BEAD 40 OHM 0805 1LN Laird-Signal Integrity Products
    1 HEATSINK TO-220 W/PINS 1.5"TALL Aavid Thermal Division of Boyd Corporation
    1 CONN PWR JACK 2X5.5MM 24V 2.5A SOLDER CUI Inc.
    1 CONN HEADER VERT 4POS 2.54MM Harwin Inc.
    1 CONN USB MICRO B RECPT SMT R/A Amphenol ICC (FCI)
    4 TEST POINT PC MINI .040"D BLACK Keystone Electronics
    1 Test Sockets SINGLE PCB SOCK RED Deltron
    5 TEST POINT PC MINI .040"D WHITE Keystone Electronics
    1 Test Sockets SINGLE PCB SOCK BLACK Deltron
    1 MOUNTING KIT TO-220 Aavid Thermal Division of Boyd Corporation

    4 MOSFET N-CH 2.5OHM 60V 0.25A SOT-23 Rohm Semiconductor
    1 MOSFET P-CH 33mOHM 40V 3.3A DFN2020 Diodes Incorporated
    1 MOSFET N-CH 24mOHM 75V 80A LINEAR TO-220AB IXYS
    3 RES SMD 2K OHM 1% 1/10W 0603 Stackpole Electronics Inc
    2 RES SMD 100K OHM 1% 1/10W 0603 Stackpole Electronics Inc
    26 RES SMD 10K OHM 5% 1/10W 0603 Stackpole Electronics Inc
    1 RES SMD 12K OHM 5% 1/10W 0603 Stackpole Electronics Inc
    1 RES SMD 301 OHM 1% 1/2W 1206 Stackpole Electronics Inc
    1 RES SMD 931 OHM 1% 1/4W 1206 KOA Speer Electronics Inc.
    1 RES SMD 2.61K OHM 1% 1/4W 1206 KOA Speer Electronics Inc.
    1 RES SMD 442 OHM 1% 1/4W 1206 KOA Speer Electronics Inc.
    4 RES SMD 1K OHM 5% 1/10W 0603 Stackpole Electronics Inc
    2 RES SMD 4.7K OHM 5% 1/10W 0603 Stackpole Electronics Inc
    10 RES SMD 28.7 OHM 1% 1W 2512 Vishay Dale
    1 RES SMD 47 OHM 5% 1/10W 0603 Stackpole Electronics Inc
    3 RES SMD 0 OHM 1/10W 0603 Stackpole Electronics Inc
    1 RES SMD 75m OHM 1% 3W 2512 Bourns Inc.
    2 RES SMD 27 OHM 1% 1/10W 0603 Stackpole Electronics Inc
    3 RES SMD 20K OHM 1% 1/10W 0603 Stackpole Electronics Inc
    1 TRIMMER 100K OHM 5% 1/10W 1 TURN Bourns Inc.
    17 SWITCH TACTILE SPST-NO 0.02A 15V Panasonic Electronic Components
    1 ROTARY ENCODER MECHANICAL 24PPR Bourns Inc.
    1 THERM NTC 10KOHM 3984K RING LUG Vishay BC Components
    1 THERMISTOR NTC 10KOHM 3380K BEAD Murata Electronics
    1 IC OPAMP GP 4 CIRCUIT 14TSSOP Texas Instruments
    1 IC USB SERIAL FULL UART 20SSOP FTDI
    1 IC REG LINEAR 3.3V 1A DPAK-3 ON Semiconductor
    1 IC MPU SUPERVISOR 3.08V 20MS SC70-3 Microchip Technologies
    1 LCD COG CHAR 2X20 WH TRANSFL 3.3V Newhaven Display Intl
    1 IC MCU 32BIT 256KB FLASH 64LQFP STMicroelectronics
    1 IC DAC 12BIT V-OUT SC70-6 Linear Technology/Analog Devices
    1 IC CMOS 1 CIRCUIT SOT23-5 Texas Instruments
    1 IC MONITOR PWR/CURR BIDIR 0.5% 10MSOP Texas Instruments
    1 TVS DIODE 5.5V 10V SC88 ON Semiconductor
    1 CERAMIC RES 8.0000MHZ 10PF SMD Abracon LLC

    Manually load these parts into a cart and purchase the components.

  • 3
    Order Stencil & Solder Paste

    Once your PCB & components arrive, you will be ready to start assembling.  One critical custom tool will be the solder paste stencil which can be ordered using services like https://www.oshstencils.com/#%20.  The gerbers I have attached to this project are very conservatively designed in order to be directly compatible with these services.  You should be able to simply drop the zip file into the website and select the necessary settings..

    From OSH Stencils:

    Track the production progress and shipping until the stencil arrives.

    Also you will need solder paste.  I recommend using lead free, but be sure to investigate all of the usage warnings since it does contain chemicals.  I usually purchase my solder paste through OSH Stencils during checkout, but you can buy solder paste through many sources:

View all 9 instructions

Enjoy this project?

Share

Discussions

nike9307 wrote 12/17/2019 at 12:29 point

That project is really great. It really stands out head and shoulders above all of the other low power DC power loads in terms of user interface.

If i could just give some ideas for later versions (if you are considering making any more ofc.):
- Some sort of fan header. You can get greater currents that way, since you can get more power out of the system.
- Getting USB CDC driver is really easy using the STM32 tools (like the CubeMX). I'd personally go with one of the STM32F042 and skip the FTDI IC.  
Also your layout and documentation are really nice. Way nicer than some commercial products i've had to redesign. 

  Are you sure? yes | no

schwarzrmsu wrote 12/18/2019 at 03:02 point

Thank you for the kind words.  I do plan on coming out with future versions of the project.  

Currently finished the HW design on the EDU_1 revision (Engineering Development Unit), and working on developing SW.  I find it easiest to get the SW and test all the HW functionality on a single user friendly board.  I might go through a couple of EDU revisions before PROTO_1.  

In the proto phase I will try to design everything into more of a product.  So I will work a lot on picking a case and splitting up the design into multiple PCB's.  This is where adding a fan may be possible.  

Also I will probably look at higher power iterations once I have completed this project.  This project should give me many building blocks to make developing the higher power designs much easier.

Glad you like the project and thank you for the ideas.

  Are you sure? yes | no

nike9307 wrote 12/18/2019 at 08:25 point

You are welcome. I'm glad you liked my ideas.

I've always wanted to design a DC Power Load and once i have some free time i certainly will. Not because i need it, i have access to a very nice 300W Power Load. I just wanna make one. 
When that time comes i may steal your display. It has really easy to use form factor. 
I will probably be aiming for around 50W or so on mine. I'll probably use an old CPU cooler (LGA775 has some nice, cheap coolers) for the power transistor. Or i may go with an extruded aluminum cooler with 4-6 transistors. I dont know. 
I just had another idea - The LOAD_RESISTOR is your current measuring signal. Buffer, that signal (without the low pass filter and maybe amplified a bit) and have it go to a male BNC connector. That way you can plug your scope with a BNC-BNC Cable and see current in real time, not just averaged. Just dont forget the 50R termination. 
I'm sorry, if i'm intruding in your project, just some random ideas i have.

Best of luck with the software and with the future revisions of the board. 

  Are you sure? yes | no

Dan Maloney wrote 12/02/2019 at 16:57 point

Thanks for the great documentation. I learn a ton just looking at schematics that are nicely laid out like that.

  Are you sure? yes | no

schwarzrmsu wrote 12/03/2019 at 03:47 point

Thank you for the compliment.  I do my best to document my projects.  I have been working on a few over the past few years, but never decided on a platform to share them.  Hackaday.io seems to be exactly what I was looking for.  Slowly catching up with uploading content, but this is actually one of my newer projects.  Glad to hear other people can benefit from my work as well.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates