• Measuring the PCB Antenna

    Ville Tiukuvaara06/09/2018 at 16:04 0 comments

    The revision 3 PCBs are looking good so far. Since there are components on both sides, I soldered one side with the reflow skillet and the other side by hand.

    As shown, there are breakaway tabs for a programming header on one side and some broken out signals for debugging on the other. I made the programming header mate with the Nucleo that I've been using as a programmer. It fits nicely:

    Back to the PCB antenna. In my last post, I explained how I modified it from a TI app note, and simulated to show resonance at 915 MHz. Unfortunately, I also simulated that the impedance would not be very close to 50 ohms, requiring a matching network. This doesn't seem to be the case though. To measure S11 I soldered an SMA connector at the transceivers's ANT pin, and put a 0 ohm resistor where there is a place for a series matching inductor (L1):

    Added an SMA connector to measure S11. C22, L1, and C21 are for a matching network.

    I 3D-printed some ABS covers to put around the antenna to add the effect an enclosure. This plastic shifts the resonance and so I printed a few different thicknesses of cover.

    A plastic cover around the antenna to add the effect of having an enclosure.

    Adding thicker covers shifted the resonance lower, which is what I expected. I decided also to add some ABS material around the rest of the PCB as shown:

    ABS taped around the rest of the PCB further shifted the resonant frequency down a bit more.

    With this configuration, I found that the antenna was close to 50 ohms! I thought it was too good to be true, but this is the case. Maybe the parasitics from the unpopulated matching network worked out just perfectly to tune to 50 ohms.

    S11 for the antenna. It is sensitive to the position of the antenna, as seen by the three traces that correspond to different positions.

    The three traces have an impedances of 49.8 - j58.0 ohm, 52.4 - j1.9 ohm, and 49.3 + j17.6 ohm. Pretty much 50 ohms! No matching network required. :)

  • Revision 2

    Ville Tiukuvaara04/08/2018 at 20:13 0 comments

    As described in its datasheet, the MCP73831 LiPo battery charger is designed to detect the presence of a battery by sourcing 6 μA of current and detecting the voltage. If a battery is present, the voltage should stay below about 4.3 V. If the battery is not present, there should be a large impedance so the voltage rises past 4.3 V. Unfortunately, the first revision had the load (the LDO supplying VCC) in parallel, so to the battery charger it seemed that there was always a battery connected.

    Charging LiPos typically works in two stages: an initial constant current stage until the voltage reaches nominal battery voltage and then a constant voltage mode is entered. The MCP73831 also has a third preconditioning stage that happens before the constant current stage if the voltage is very low; this supplies a smaller constant current. I believe that having the load in parallel with the battery should still work as long as the load draws less current than provided in constant current mode. This would just mean that part of the current would be diverted from the battery but it would still at some point enter constant voltage.

    Nevertheless, I wanted to correct this in the second revision. My solution was to switch the LDO's supply to 5 V from USB once a USB cable is inserted. This is done with Q1 shown below. When USB is disconnected, the gate of the PFET is low so VIN is connected to VBAT1. I chose a PFET that has a low on-resistance. When the USB cable is inserted, the PFET turns off and VIN is supplied from VUSB1 through the Schottky diode (which has a forward voltage less than a regular diode).

    I the second revision, I also wanted to try out a "stacked" approach, with two PCBs mounted on top of each other. I did this by laying out two PCBs with matching dimensions and header connector. They were connected with mouse bites so I did not need to pay for fabricating two PCB designs. I also added a programming portion connected with mouse bites that can be snapped off after programming. 

    Revision 2, after snapping apart and connecting withheaders.
    Revision 2, before snapping apart.

    I tried connected it up and it seemed fine before I snapped it apart. However, after snapping it apart and connecting it together, it seemed that the ground on one of the headers was not connected! KiCAD had told me that there were no unconnected nets. However, it turned out that one of the "connections" was through the ground plane through the mouse bites connected the three parts together.

    Onto revision 3! In revision 2 I ditched the RFM95W and battery gauge but I plan to add these back in revision 3. I think I'll also go back to a single 4-layer board, but with components on both sides so I can make it more compact.

  • Success with the SD Card!

    Ville Tiukuvaara12/21/2017 at 03:09 0 comments

    After quite a bit of frustration, I have finally gotten writes to the SD card working! As I mentioned in my previous log, I am using the 4-bit interface available on SD cards, rather than the simpler SPI interface used in most hobby projects. This allows more data throughput - I have it running at 48 MHz after initialization which must be done at 400 kHz or less. It turned out that my problem was leaving the signals floating. After pulling high (internally with the microcontroller) I was successful. This answer on Stack Exchange has more about this.

    Saving Audio

    With that issue resolved, I thought it would be neat to capture audio from the MEMS microphone and save it to the SD card. I took the USB audio streaming demo from STMicroelectronics that I mentioned in my previous post and modified it so that it saved data from the audio stream to the SD card. I found that SD writes were at first taking too long, resulting in horrible sounding audio because many samples were being dropped. I did two things to solve this:

    1. Increase the buffer length for SD writes. SD writes occur in multiples of the card sector size (usually 512 bytes) so writing less (or writing without alignment to the 512-byte segments) results in overhead.
    2. Use double buffering. I used two buffers, so that SD card writes can occur using one buffer while audio is still being recorded to the second buffer.

    Here is a snippet of code that demonstrates the double buffering, starting with some global variables:

    wave_sample_t PCM_buffer[AUDIO_PCM_BUFFER_LENGTH];
    wave_sample_t SD_buffers[2][AUDIO_SD_BUFFER_LENGTH];
    bool audio_ready = false;
    uint32_t SD_buffer_pos = 0;
    uint32_t SD_buffer_num = 0;

    The double buffering is done with SD_buffers[0] and SD_buffers[1] (and wave_sample_t is a 16-bit type for PCM). And a snippet from the application:

    uint32_t start = HAL_GetTick();
    uint32_t total_samples = 0, current_samples = 0;
    
    while(HAL_GetTick() < start + millis)
    {
        if(audio_ready)
        {
            current_samples = SD_buffer_pos;
            SD_buffer_pos = 0;
            total_samples += current_samples;
    
            // Switch to the other buffer while writing out this buffer
            SD_buffer_num = (SD_buffer_num + 1)%2;
            audio_ready = false;
    
            if(logger_wav_append(file, current_samples, SD_buffers[SD_buffer_num]) != LOGGER_OK)
            {
                BSP_AUDIO_IN_Stop();
                return AUDIO_ERROR;
            }
        }
    }
    
    BSP_AUDIO_IN_Stop();
    if(logger_wav_write_header(file, AUDIO_SAMPLING_FREQUENCY, 1, total_samples) != LOGGER_OK) return AUDIO_ERROR;

    The line with modulus operation switches the buffer. This loop waits for audio_ready, which is set by the interrupt handler that fires when audio is ready for processing. It writes takes the audio and copies it to SD_buffers[n].

    void BSP_AUDIO_IN_TransferComplete_CallBack(void)
    {
        if(audio_ready) return;
    
        if(SD_buffer_pos + AUDIO_PCM_BUFFER_LENGTH < AUDIO_SD_BUFFER_LENGTH)
        {
            memcpy(SD_buffers[SD_buffer_num] + SD_buffer_pos, PCM_buffer, AUDIO_PCM_BUFFER_LENGTH*sizeof(wave_sample_t));
            SD_buffer_pos += AUDIO_PCM_BUFFER_LENGTH;
        }
    
        if(SD_buffer_pos + AUDIO_PCM_BUFFER_LENGTH >= AUDIO_SD_BUFFER_LENGTH) audio_ready = true;
    }

    Thus when the SD_buffer[n] is full the main application code knows to write to the SD card since audio_ready is set to true.

    WAVE File Format

    To actually save the data to the SD card, I decided to use the WAVE file format. This format can be used as a container for the raw uncompressed PCM data, so no processing needs to be done on the microcontroller. I am currently recording at 32 kHz with 16-bit samples, which sounds very decent. Other than the PCM data, the WAVE file has a 44-byte header that is described here

  • A first look at the PCBs

    Ville Tiukuvaara12/05/2017 at 03:58 0 comments

    Soldering at Home

    I ordered and received a batch of five PCBs and a stencil from EasyEDA a few weeks ago, and have since soldered them together and done a little bit a programming. With the large number of surface mount components, I decided to try my hand at the reflow skillet method with a 40% success rate so far. Well it's really 0% because all of the them had shorted pins and needed rework, but that is to be expected.

    Reflow skillet soldering
    Using an IR thermometer to heat the PCB to 250 celsius.
    Reflowed PCB
    There was plenty of rework required after reflowing. Many shorted pins and some misaligned components are visible.
    First reflow attempt
    My first attempt at hot plate reflow soldering was disastrous and resulted in a bad smell at home for the rest of the day. Now I do this in the garage.

    I used SAC305 (lead-free) solder paste, which melted at around 200 celsius. I quickly found out that it's important not to go much above 250 celsius since I melted one of the PCBs. Afterwards I fixed up the shorted pins with a microscope, soldering iron, and some solder wick. I was able to program three of them, although one of these stopped working.

    Lessons learned so far:

    1. Make sure there are test points for all important signals. I only had one VDD connection (through the programming header) and wish a had a dedicated 2-pin header for power.
    2. The NRST pin on the STM32 micro controller needs a decoupling cap. It is internally pulled high, but this is needed to prevent unwanted restarts. So far I have been hooking up a Nucleo programmer to debug, and I'm guessing it also pulls NRST high.
    3. Avoid through-hole components. Because of the through-hole pin header, I was unable to do any reflow soldering after connecting it.

    SD Card Woes

    With two programmable boards, I tried to get the SD card working (firmware repo is here). SD cards support three forms of communication: 1-bit SD, 4-bit SD (for increased throughput), and SPI (easier and more commonly used by hobbyists). The STM32L476 has an SDMMC peripheral that allows the 1 and 4-bit modes to be used. I used the CubeMX software from ST to generate the backbone code for the project and then used the CubeMX importer (a python script) from Carmine Noviello to import it into a project for working with the ARM GNU plugin in Eclipse. This is all described his book, which I recommend.

    CubeMX
    CubeMX makes it easy to set up a project. It even configures FATFS (although I am getting skeptical that it's doing it correctly).

    CubeMX also allows FATFS to be configured to use the SD card, so it was quite easy to get the project set up. FATFS is a library for working with FAT16/exFAT filesystems. My plan is to use it to store audio recordings from the onboard mic onto the SD card. Unfortunately, it is not so easy to get FATFS working. I have so far gotten 1-bit mode to work on an SDHC card (SDHC is the second SD card standard for cards up to 32 GB) but not on an SDSC card (older standard for <4GB). SD cards have a microcontroller and a state machine, and require a careful initialization sequence including checking the supported voltage. This initialization happens in 1-bit mode at <400 kHz, after which a command (ACMD6) can be sent to switch to 4-bit mode for more throughput and the clock frequency can be increased. So far the performance has been very inconsistent. I was able to switch to 4-bit mode perhaps once. I am not sure if this is because of the SD clock frequency I am running at, which I have experimented with seemingly no improvement. I have tried frequencies from 100 kHz to >20 MHz.

    In 1-bit mode, where I am able to initialize the SD card, I am then unable to write a file, using a FAT16 file system. While FATFS is able to create a new file, it is unable to write to it. Checking the SD card afterwards, there is a new empty file. Since it has created the file (with a name) it seems that FATFS is able to write to file allocation system but then unable to correctly write to the cluster containing the file. It could also be...

    Read more »