# USB Power Meter
## Hardware Design
A cursory reading of the official schematics shows that the USB power meter detects current and voltage through ADC, and then obtains the power value through the formula that power equals voltage multiplied by current, and finally displays the value on the display screen. Therefore, we dissect the overall circuit into five parts and explain them separately.
````c
1. Main control circuit: main control chip + decoupling circuit + BOOT circuit + reset circuit + crystal oscillator circuit + SWD circuit + serial port circuit;
2. Current sampling circuit;
3. Voltage sampling circuit;
4. Power supply circuit;
5. Display circuit.
````
----
### 1. Main control circuit
The main control used in this USB power meter is the chip N32G430C8L7 from National Technology, which is sold for 5 yuan in the mall. In this era of "chip shortage", MCUs with a five-yuan M4 core are probably rare. Although this material is very powerful, our power meter actually only uses the USART, ADC, and IIC functions, and other functions are not used. Among them, the serial port is not for printing information, but for serial port Boot download. Of course, since you use the SWD circuit interface, the serial port is not actually used. Of course, if you say you want to use the serial port to download the program, there is no problem, but it is worth noting that **If you use the serial port program to download, you need to pull up the BOOT0 pin! ! ! **
![1.Serial port program download.png]

#### However, I personally prefer to use the SWD circuit for downloading, which is much more convenient, so you can choose your favorite download mode according to your personal preferences.
---------
The main control circuit part mainly leads to **serial port pins, SWD pins, BOOT0 pins, crystal pins, reset pins, voltage sampling pins, current sampling pins, and IIC pins**. It is worth noting that the IIC communication routine uses software IIC, that is, ordinary GPIO simulates IIC timing communication to perform OLED communication functions, so the choice of IIC pins can completely choose two GPIO pins at will.
![2. Main control circuit.png]

It is worth noting that: **It is not necessary to use certain pins, there are other pins that can be selected, please refer to the data sheet in the reference document for details<-**
----
### 2. Decoupling circuit
Through the observation of the main control circuit MCU, it can be seen that **There are 4 VDD pins, so at least 4 0.1uf capacitors should be placed next to them! **Some people may ask what 0.1uf is, because we know that in the circuit, the frequency f=1/(2×Π×root (LC)), so **If the capacitance value is small, the frequency is high, and high-frequency clutter is filtered out; if the capacitance value is large, the frequency is low, and low-frequency clutter is filtered out. **
![3. Decoupling circuit.png]

#### It is worth noting that: The design of the official hardware development board specifically states that **The first pin of N32G430C8L7 must be guaranteed to have a 4.7uf capacitor and a 0.1uf capacitor, and the remaining capacitors must be 0.1uf capacitors**, so we need to pay extra attention to this point. I heard that if we don’t do this, the MCU may not be normal! To be on the safe side, I still added it, hahaha, the specific schematic diagram is as follows.
----
### 3. BOOT circuit
#### I believe that anyone who has studied microcontrollers should know that the BOOT pin is used to select the boot mode of the **chip MCU**, mainly: 1. Boot from the system flash memory; 2. Boot from the system memory; 3. Boot from the internal SRAM. Among them, the most commonly used is the first method, which is the mode we often use to download and start the SWD circuit; the second mode is to burn the bin file through the serial port and burn it by adjusting the BOOT pin, which is a little troublesome. I haven't tried the third method. I remember that when I watched Hard Rock Technology's explanation before, it seemed to mention this. This download method is not recommended. I forgot the details. Students who understand can tell me one or two below. In summary, I chose the first mode. Of course, I also introduced the second mode. You can choose it yourself. The specific schematic diagram is as follows.
![4.BOOT circuit.png]

#### Here I use two 0603 package resistors to switch the mode; in the default state, I only installed the R4 resistor, and the R3 resistor was not connected, that is, BOOT0 was pulled low by default, and the program was downloaded through the SWD circuit interface. Some students may want to download via the serial port. At this time, just solder the zero-ohm resistor R3, and the BOOT0 pin will be pulled high, so that you can enter the serial port download mode. I have already explained this before. The overall design is also to ensure the miniaturization of the circuit.
---
### 4. Reset circuit
#### The purpose of the reset circuit is to ensure that the chip restarts and resets manually; the circuit is very simple, and it still uses the most commonly used **hardware debounce** button design scheme on the Internet. The specific schematic diagram is shown below. It is worth noting that there are requirements for the reset duration. For details, refer to the chip's **-> 4.3.13 NRST pin characteristics in the data sheet <-**. The time calculation formula for RC hardware debounce is **t=RC** in analog electronic technology. The manual says that the duration of the reset pulse is at least 10us, so when choosing the resistance and capacitance values, you can consider it to avoid abnormal reset.
![5. Reset circuit.png]

#### The delay time here is **t=10×10^3×100×10^-9=1ms, which is far more than the time required by the system**.
----
### 5. Crystal Oscillator Circuit
#### In fact, there are many principles for selecting crystal oscillators, and there are many explanation methods on the Internet. I have not studied this part in depth. Generally, the most commonly used load capacitor of large manufacturers is generally **20pf**. You can use an oscilloscope to test the waveform, which may be more intuitive. Here, based on the materials and previous usage, I actually used **22pf**. The specific selection is based on the specific selection. If you are interested, you can go to the Internet to check it out. The specific schematic diagram is shown below.
![6. Crystal Oscillator Circuit.png]

---
### 6. SWD Circuit
#### The lead-out of this part is mainly for downloading circuits. By checking **->The pin definition in the data sheet<- **, you can see that PA13 and PA14 are used as SWDIO-JTMS and SWCLK-JTCK. We only need to lead out these two interfaces! It is worth noting that: **some documents suggest adding RSET pins to the SWD circuit to prevent the chip from locking**. Considering the overall size and symmetry of the product, I did not add it here. You can consider it yourself. The specific schematic diagram is shown below.
![7.SWD circuit.png]

----
### 7. Serial port circuit The serial port
lead-out is mainly used for **serial port downloading programs**, of course, it can be used for serial port communication without any problems! The specific schematic diagram is shown below.
![8.Serial port circuit.png]

---
### 8. The current sampling circuit
is first powered by the Type-A male connector, and then output through the Type-A plug.
![9. Current sampling circuit.png]

The current sampling part is the **INA199B1DCKR** current sensing amplifier with a fixed gain of 50V/V, which will be used in the program code. If you use other sampling chips, the amplification factor may be different, and the program needs to be changed.
This sampling uses the **low-side sampling** method, that is, the sampling resistor is connected to the GND loop. This design can calculate the complete differential, follow, amplify, and output when the differential signal is sent to the op amp.
If high-side sampling is used, that is, the sampling resistor is placed at a high position between the power supply and the load, although this placement not only eliminates the ground interference generated in the low-side detection scheme, but also detects accidental short circuits from the battery to the system ground, but high-side detection requires the detection amplifier to handle common-mode voltages close to the power supply voltage. This common-mode voltage value range is very wide, ranging from the level required to monitor the processor core voltage (about 1V) to hundreds of volts commonly seen in industrial, automotive, and telecommunications applications. Application examples include typical laptop battery voltage (17 to 20V), 12V, 24V or 48V batteries in automotive applications, 48V telecommunications applications, high-voltage motor control applications, current detection for avalanche diodes and PIN diodes, and high-voltage LED backlights. Therefore, an important advantage of high-side current detection is that the detection amplifier has the ability to handle large common-mode voltages.
Therefore, the current sampling method of sampling resistor plus op amp is best performed at the low end. Although low-end sampling will affect the ripple of the signal due to common ground interference. But compared to the high-end, the solution is simple, low-cost and highly reliable.
----
### 9. Voltage sampling circuit
#### The hardware circuit part mainly uses the most basic voltage divider formula to obtain the coefficient value. I will explain this coefficient value in detail in the program part. The choice of this resistor is also very critical. Different resistors will require the factor value of the program code to be changed! The official ones are 91K and 10K, but I only have 110K and 10K, so I replaced the official hardware diagram. There will be some changes in the program code. I will elaborate on the specific calculation formula in the program part. Here it is just a display of hardware design.
![10. Voltage sampling circuit.png]

----
### 10. Power supply circuit
The power supply circuit is very simple. It is just an LDO. It is mainly used to power the MCU chip. We check the chip's **-> 4.3.1 General working conditions in the data sheet<-** and find that the standard working voltage of the chip is 2.4V-3.6V, so we need to convert the input 5V power supply voltage into 3.3V to power the chip. I believe that the most commonly used one is **AMS1117-3.3V**, and I am the same. Considering the material situation, my hardware circuit is also this material.
#### But there is a problem: the size of this material is relatively large, so I wired it to the back, which may not be suitable for the patch process, so you can consider it yourself. I soldered it manually~~ (mainly because I have no money)~~.
![11. Power circuit.png]

----
### 11. Display circuit
#### The display part uses **OLED 0.91-inch screen**. Here I would like to thank **XCC** for letting me get a screen for free, hahahaha. The circuit part is very simple, just use **2.54mm pitch 4P female header to lead out, and then plug in the OLED module**. The specific schematic diagram is shown below.
![12. Display circuit.png]

----
### 12. Overall 3D model
![13. Overall 3D model.png]

Here I will explain how to add OLED to the 3D model of this pin header.
The first step is to select the H1 terminal, in the properties on the right~~(shortcut key is: })~~encapsulation, click it, and then you will enter the package manager.
The second step is to change the package of the H1 terminal to **0.91OLED screen v2**.
#### The third step is to adjust the position of the OLED. My parameters are as follows. Please refer to your own hardware design for details.
![14.OLED adjustment parameters.png]

----
### 13. Proofing physical picture
#### The above is the process of all hardware circuit design, proofing, and the physical picture is shown in the figure below.
![15. Proofing physical picture.jpg]

-----------------
##
At the beginning of the software design, I wanted to test the peripherals of **N32G430C8L7**, but! I found that I only led out the serial port and OLED pins, and the others were not led out, so there was no way.
I have given a new project directory here. Later, you can add a folder by yourself and run it.
Next, let's analyze the official code, and later you can also modify the program code for different hardware circuits.
----
First, go through main.c and you will find that watchdog, software simulation IIC and ADC are used. Watchdog and IIC are the most basic, so we don't need to introduce them too much. For example, IIC actually uses the folders in Lib/MonoScreen and Lib/SoftI2C to realize the display function of OLED. SoftI2C is a function that simulates IIC timing, and then calls it in MonoScrren. Fonts is even simpler, it is a font library, so we don't need to explain this part too much. The most important thing is the **sampling part code**.
```c
// Define the ratio of 1LSB of ADC to the actual voltage and current
const float volFactor = 8.471446586200685F * VOLTAGE_FACTOR;
const float curFactor = 1.646382291543582F * CURRENT_FACTOR;
```
First of all, the meaning of **volFactor** is: voltage factor, which means **actual voltage divided by sampled voltage**.
The quantity VOLTAGE_FACTOR is actually 1, which is similar to the function of a filter sampling~~ (Maybe, I personally understand it, haha. Then we have to pay attention to how the previous value is obtained.
````c
What we know is that the power supply voltage of the sampling chip is 3.3V, and the sampling is adc, analog-to-digital converter, and the sampling bit is 12 bits, so there is such a corresponding formula:
3.3V 2^12-1=4095
If we assume that the value collected by adc at this time is adc, then what is the analog quantity x at this time? Therefore, we have:
x adc
According to the corresponding relationship:
x = adc × (3.3/4095)
Please remember that the value of x is not the actual value at this time. Why? Because in the sampling circuit, there is a conversion formula for voltage division! If we explain it here, we can still analyze it based on the official resistor. According to the voltage division formula:
Vadc = 10K/(10k+91k)×Vbus, where Vbus is 5V.
So if the adc voltage has been collected, how to calculate the current Vbus value?
Vbus = Vadc / (10K/(10k+91k)) = Vadc×(10+91)/10
OK, since we can reach this formula, it is easy to say. Now we collect Vadc=x based on adc, then Vbus at this time has a corresponding relationship with x, as shown below.
Vbus = Vadc×(10+91)/10 = x × (10+91)/10 = adc × (3.3/4095) × (10+91)/10
For the convenience of program running, we will calculate the value ourselves, so it can be:
Vbus = adc × 8.139194139
As for why the official value is 8.47, it may be based on the actual voltage test, because it is said to be 3.3V, but the actual voltage may not be exactly 3.3V.
````
We have solved the origin of the volFactor value, and now let's take a look at the origin of curFacotr.
````c
What we know is that the power supply voltage of the sampling chip is 3.3V, and the sampling is adc, analog-to-digital converter, and the sampling bit number is 12 bits, so there is such a corresponding formula:
3.3V 2^12-1=4095
If we assume that the value collected by adc at this time is adc, then what is the analog value x at this time? Therefore, we have:
x adc
According to the corresponding relationship, we have:
x = adc × (3.3/4095)
Please remember that the value of x is not the actual value at this time. Why? Because in the sampling circuit, the current has undergone gain conversion.
We can find out from the data sheet of the current sampling chip that the chip has a full-scale shunt voltage drop of 10mV, which means that for every change of Iadc by 1, ▲I=10mV, so there is the following corresponding formula:
1 10mV
Then, if the current sampling value is Iadc at this time, what should be the displayed x?
Iadc x × 50According
to the corresponding relationship,
x × 50 = Iadc × 10
---> x = Iadc × 10 / 50Substitute
the current sampling value, and we can get the relationship between x and adc:
x = Iadc × 10 / 50 = adc × (3.3/4095) × 10 / 50In
order to facilitate the program running, we will calculate the value ourselves, so we can get:
x = adc × 1.611721612As
for why the official value is 1.64, it may be based on the actual voltage test, because it is said to be 3.3V, and the actual voltage may not be exactly 3.3V.
````
-----
After obtaining the corresponding coefficient factors, several variables are defined:
```c
// Define ADC sampling values of voltage and
currentuint32_t volRaw = 0, curRaw = 0;
// Define voltage and current values, unit mV/mA
uint16_t voltage = 0, current = 0;
// Define the power value in milliwatts
uint32_t power = 0;
```
Among them, volRaw and curRaw are the values obtained through adc sampling; voltage, current, and power are actual values, that is, the sampled values multiplied by the coefficient factor.
````c
// Sampling ADC values of voltage and current, 16x oversamplingvolRaw
= 0;
curRaw = 0;
for (int i = 0; i < 16; i++)
{
volRaw += BSP_ADC_GetData(VOLTAGE_ADC_CHANNEL);
curRaw += BSP_ADC_GetData(CURRENT_ADC_CHANNEL);
SysTick_Delay_Ms(20);
}
volRaw >>= 4;
curRaw >>= 4;
// Calculate the actual voltage, current and powervoltage
= volRaw * volFactor;
current = curRaw * curFactor;
power = current * voltage / 1000;
````
Sixteen times sampling is also to ensure the stability of sampling. Read the adc sampling values 16 times, and then divide them by 16. The average value represents the voltage and current values at this time to ensure the stability of the obtained values! The
rest of the main.c code is the displayed content, and there is nothing much to say here. Overall, it is which coefficient factor is more difficult to understand! I hope it helps you.
-----
## Actual test picture
! [16. Actual test picture.jpg]

-----
## Problems encountered
### Problem 1
Problem 1 is: After soldering, the OLED does not light up!
Solution: The official IIC drives the OLED with **PA4, PA5**, and the IIC drive OLED pins of the power meter I designed are: **PB13, PB14**, so the code needs to be changed. What I show here is the changed code!
The first change: in the MonoScreen.c file
````c
#define I2Cx I2C1
#define I2Cx_SCL_PIN GPIO_PIN_13
#define I2Cx_SDA_PIN GPIO_PIN_14
#define GPIOx GPIOB
````
---
Change the second place: In the MonoScreen.c file, the clock start function and the pin setting function need to be changed to GPIOB.
### Problem 2
Problem 2: After changing the pin definition in the code, the OLED still does not light up.
Solution: The official code uses the internal high-speed clock of the **chip** as the system clock of the program, and we welded an external high-speed clock, there will be a bug, there are two solutions: 1. Remove the external high-speed clock; 2. The program code.
I won’t talk too much about the first method, just remove the crystal oscillator and the debt capacitor! Then the OLED will light up.
The second method is to use the external high-speed clock as the system clock, which is also the method I finally adopted after repeated tests.
I also used method 1, and it worked fine. However, in order to make the development board look good, I still soldered the external high-speed crystal oscillator. As a result, the screen did not light up, so I started to modify the code.
It mainly adds one line of code. The specific code is as follows:
````c
void SetSysClockToHSE(void)
{
RCC_Reset();
RCC_HSE_Config(RCC_HSE_ENABLE);
HSEStartUpStatus = RCC_HSE_Stable_Wait();
if (HSEStartUpStatus == SUCCESS)
{
FLASH_Prefetch_Buffer_Enable();
if (HSE_Value <= 18000000)
{
FLASH_Latency_Set(FLASH_LATENCY_0);
}
else
{
FLASH_Latency_Set(FLASH_LATENCY_1);
}
RCC_Hclk_Config(RCC_SYSCLK_DIV1);
RCC_Pclk2_Config(RCC_HCLK_DIV1);
RCC_Pclk1_Config(RCC_HCLK_DIV1);
RCC_Sysclk_Config(RCC_SYSCLK_SRC_HSE);
while (RCC_Sysclk_Source_Get() != RCC_CFG_SCLKSTS_HSE)
{
}
}
else
{
while (1)
{
}
} }
`
```
Then put this function in main.c and call it, and then the screen will light up!
---
### Problem 3
Problem: After trying all the above attempts, the OLED still does not light up.
Solution: The board is poorly soldered. Add more solder and tap each pin again. I have tried this and there is no problem later.
----
### Problem 4
Problem: The value displayed by OLED is not standard. When given 5V, it displays 4.something volts.
Solution: The main problem here is that some people’s hardware is different from the official value, resulting in inaccurate display. The solution is to change the coefficient factor of the program. I have explained in detail how to calculate it before, so I will not repeat it here.
----