Blood Pressure Monitor (A3051) Development and Production

© 2024 Kevan Hashemi, Open Source Instruments Inc.


Contents

Modifications
Development
2024

Modifications

[22-NOV-24] We are beginning with the A305101C PCB and S3051B schematic. No modifications yet.

Development

Chronological record of the development and production of the Two-Channel Subcutaneous Transmitter (A3047).

2024

[27-FEB-24] Create manual page.

[05-JUL-24] We find that our first run of A3050 circuits uses 1.2V as VCC for the programming connector. Our logic core power supply uses 1.2V but since its I/O banks are connected to VA we have to sever the track going to the programming connector and solder a wire link from VA to pin 1 of the programming connector. Using 1.2V as VCC resulted in us damaging multiple LCMX02-1200ZE logic chips; we note that the programming cable from the computer tries to pull VCC high and fails to program. We also note that the reference clock oscillator has its pads in the incorrect place causing its landing pattern to be incorrect. We will change this footprint on future layouts but will use an external function generator signal into a test pin for the time being.

[11-JUL-24] We load everything needed to power the A3051 board as well as the pressure sensor but nothing else on the circuit. We note that the pressure sensor consumes roughly 1.5 μA in its default state. We also note that pins IDY, SCL, and SDA are all at roughly 300mV. This implies that each of these pins has an internal pull-up resistor of 100 MΩs to its power supply. The pin SA0 on the other hand sits at roughly 2.7 V implying it has a 1 MΩ pull-up resistor to its power supply. These measurements were taken using a 10 MΩ oscilloscope probe.

[22-JUL-24] We find that our footprint for the pressure sensor is incorrect. Provided by the datasheet is a bottom view of the sensor, not a landing pattern for the footprint as we had initially thought. We design a new PCB with the correct sensor footprint, the correct oscillator footprint, and the correct voltage applied to VDD of the programming connector.

[22-NOV-24] We build an A3051A with our new A305101C printed circuit board. The programming connector now provides VA on P1-1. We drop C2 and C3 to 1 μF. We raise C1 to 22 μF. We are unable to program the logic chip unless we short U2-5 to U2-4. The voltage drop across U2 during programming otherwise drops VA to below 2.4 V and U3 cuts off the 1V2 supply to the logic chip. The oscillator footprint is still wrong: U6-3 has been exchanged for U6-1. We connect the two with a wire link so as to deliver RCK to U4. After programming, we can start the logic chip by shorting U2-5 to U2-4. Otherwise we see oscillations on VA with period 200 μs. We raise C3 to 22 μF, oscillations persist during power-up, although now with period 500 μs. Clean and dry. Connect power, jump-start with short from U2-4 to U2-5, now see RCK stable on TP1 and FHI on TP2. No VCO connected, nor sensor, but current is 128 μA for 128 SPS. Load MAX2524 and find DAC pins are in reverse order, so swap them in firmware. We are using commit 4340fb as a starting point. Load pressure sensor. After jump starting, TCK period is 198 ns. Reception 128 SPS, transmit value constant 32767. Current consumption now 135 μA.

We increase max_tcd in ROM.asm to 31. Our previous value of 15 was too low. Our U4 is speed grade 1, faster than the chip for which we chose the previous value. With value 15, the program decremented the divisor to zero, then went to 255, and dropped from there down to some value between 15 and 31. The calibration took about three seconds. Now it takes a fraction of a second. Our RF center frequency is 918 MHz, and TCK period is 207 ns from the calibration. Reception is poor. We observe VA to be dropping by 150-mV during transmission, which affects TUNE, on account of TUNE being derived from VA. We increase to C2 = C3 = 22 μF and reception is perfect. Drop to C2 = C3 = 10 μF and reception remains perfect. When we plug a CR2032 battery into the board, we do not need to jump start with C1 = C2 = 1 μF, but with 10 μF and 22 μF we do need to jump start.

No sensor interface yet: we are reading zeros from the disabled sensor interface, and transmitting them as 32767. But transmission is working without scatter, and current with sensor in standby looks good. Tag firmwarwe v2.1.

[23-NOV-24] With VB = 2.9 V and U3 = TPS70912, the A3051 circuit will not start up unless we jumper U2-4 to U2-5. The startup current passing through the internal resistance of U2 causes VA to drop below 2.4 V. We connect our A3051 directly to our bench-top power supply, with no ammeter, and obtain the following traces.


Figure: Power-Up Failure with VB = 2.9 V. Yellow: VA 500 mV/div. Blue: 1V2 500 mV/div. Green: VB 20 mV/div AC. Timebase 500 μs/div. We have U3 = TPS70912.

We load MCP1711T-12I for U3. This device is a pin-compatible micropower 1.2-V regulator, but it's maximum drop-out voltage at 50-mA is only 1.23 V, compared to 2.4 V for the TPS70912. Now the A3051 circuit powers up without any difficulty, see traces below.


Figure: Power-Up Success with VB = 2.9 V. Yellow: VA 500 mV/div. Blue: 1V2 500 mV/div. Green: VB 20 mV/div AC. Timebase 250 μs/div. We have U3 = MCP1711T-12I.

We place a 10-Ω resistor in series with our 2.9-V VB supply and obtain the above traces again, so as to measure the in-rush current at startup.


Figure: Startup Current, Measured with 10-Ω Series Resistor. Yellow: VA 500 mV/div. Blue: 1V2 500 mV/div. Green: VB 50 mV/div AC. Timebase 250 μs/div. We have U3 = MCP1711T-12I.

Our VB = 1.9 V drops by 200 mV with the 10-Ω series resistor, so our inrush current is 20 mA, relaxing to 5 mA in 4 ms. Quiescent current when powered up is 129 μA. In the P3051 firmware, we add PSCK, a 500-kHz clock to use with the I2C interface with the pressure sensor.

[02-DEC-24] We are studying the I2C interface of the LPS28DFW. The data sheet provides no complete waveforms. We present the four elemental tokens of the protocol below, as well as the complete byte write exchange.


Figure: I2C Interface. Top: Start (ST), Repeat Start (RS), Stop (SP), and Data tokens. Below: Waveforms for a byte write to sensor with I2C address A6..A0, byte location within sensor S7..S0.

The Serial Data Access, SDA, line has a pull-up resistor. The Serial Clock, SCL, is always driven by the master either HI or LO. We refer to a positive pulse on SCL as a "clock pulse". The master transmits an ST token to begin the exchange. It transmits A6..A0 to select a sensor, and a zero-bit for WRITE. During each data bit transfer, the master drives SDA and then transmits a clock pulse. Once the seven bits have been transmitted, the master releases SDA and the slave should drive SDA LO. The master transmits a clock pulse, and during this clock pulse, SDA must remain LO. At the end of the clock pulse, the slave must release SDA. This transmission of a one-bit from slave to master is a slave acknowledgement, or SAK. After receiving the SAK, the master transmits the sensor's internal register address S7..S0. It reads another SAK bit and transmits eight data bits. It receives a final SAK, drives SDA LO, drives SCK HI, and releases SDA, to complete an SP token. This final release is the ST token. We can write multiple bytes to consecutive addresses by refraining from transmitting a ST token, and instead transmitting another eight data bits, waiting for another SAK, and repeating until we have transmitted as many bytes as we like, ending with an SP.

A read access begins with the same transmission of six sensor address bits, a write bit, a SAK, seven register location bits, which the data sheet calls SUB for "sub-address", and a second SAK. The access transforms into a read access by transmission of a repeat start token, RS, followed by the sensor address and a read bit. A SAK from the slave follows this eight-bit transmission, and now the master knows the slave is going to drive SDA during the eight subsequent clock pulses. The slave transmits D7..D0 and releases SDA. The master can now transmit a stop token, SP, to end the access. Or the master can indicate to the slave that it wants to read another byte, and this it does by transmitting a master acknowledgement, or MAK bit. The master drives SDA LO and transmits a clock pulse. The slave will now drive SDA during the eight subsequent clock pulses.

The maximum SCL frequency supported by the LPS28DFW is 1 MHz, with minimum SCL LO pulse length 0.5 μs and minimum HI pulse length 0.26 μs. The A3050's OSR8 microprocessor runs at 5 MHz in boost mode, so one SCL cycle is five clock cycles. We might be able to read out the sensor fast enough with instructions from the microprocessor, so we eliminate the Sensor Controller and Sensor Interface processes from our firmware and replace them with a bit-wise SDA and SCL interface, and write these bits separately with instruction cycles in a process known as bit-banging.


Figure: Start, Seven Bits, Stop. A first pass at bit-banging the interface.

Our initial efforts produce an SCL period of 6.5 μs, which is 32.5 clock cycles. Looking at the code, we count 32 cycles. Bit frequency is 153 kHz. At this rate, a 16-bit read consisting of around 50 bits will take 300 μs, during which time the microprocessor will be running at 5 MHz in BOOST and consuming roughly 2.5 mA. At 128 SPS, we will be in boost for 330/7800 = 4.2% of the time and consuming 105 μA extra due to boost.

Instead of bit-banking, we consider "state-banging", where we have a register we can write to to generate a state of SDA and SCL. There are six states we are interested in for driving SDA and SCL. These are 00, 10, 01, 11, Z0, and Z1, where we have given two logic levels signifying SDA and SCL respectively for each state. If we denote bit seven of our accumulator as A, we could implement these with four locations: A0, A1, Z0, and Z1. We can now right eight bits in 80 clock cycles, assuming we have the eight bits in A to start with. Each bit is three writes to register plus a right-rotation. Our SCL period on writes is now only 2 μs. When reading bits, we can get the read bit into A0 with 13 clock cycles, but we somehow have to add the new bit to an accumulating byte. To do that we need another 12 cycles, making 25 in all. To read sixteen data bits we must transmit around 30 bits and read 20, for 800 cycles, or 160 μs.

[03-DEC-24] We are writing A7 to SDA, pulsing SCL, shifting A left, and so on, to transmit eight bits. We have the code in-line with no procedure calls. We have added four additional control registers to the sensor interface, those that implement 00, 01, 10, and 11. These save a little time, as we don't have to load any particular value into A when we write to the register.


Figure: I2C Byte Write. We begin with an ST token, proceed with 8 bit tokens, receive an SAK token, and end with an SP token.

We see sensor is driving SDA LO for an SAK during the ninth SCL pulse. When SCL goes LO, the sensor releases SDA, which begins its ascent to HI immediately, but is pulled down again 3 clock cycles later by the master. Current consumption is 130 μA, which is only slightly greater than the 128 μA we see with transmission. We add further byte exchanges until we compose a single-byte read from location 0x0F on the sensor, from which we read back the value 0xB4, which is correct. Current consumption is 145 μA.

[04-DEC-24] We remove the 10 and 11 tokens. The I2C protocol requires that no master or slave ever drives the SDA line HI. When we want to transmit a HI, we set SDA to Z instead of driving it HI, and trust that the pull-up resistor we have enabled on SDA in the logic chip will be sufficient to ensure a HI logic level by the time the master transmits a HI on SCL. From what we see in the above trace, the rise time of SDA with the pull-up resistor is about 500 ns.


Figure: I2C Sixteen-Bit Read. Blue: SDA 2 V/div. Yellow: SCL 2 V/div. Top traces 10 μs/div, bottom traces 2.5 μs/div. RS = Repeat Start. Address and data bits labelled 0 and 1. SAK = Slave Acknowledge. MAK = Master acknowledge.

We read the two bytes at 0x0F and 0x10. The first has a fixed value 0xB4. The second has a default value 0x00. We read the two bytes at 0x0E and 0x0F. The first has default 0x00. In both cases, we get the correct bits on oscilloscope, and receive them correctly by telemetry. Current consumption 151 μA.

We have deduced from examining the way the slave drives SDA that there is a delay between SCL going LO and the slave driving SDA LO, but the slave does not wait for the next SCL HI pulse before driving. We clock the slave data bit into a shift register on the rising edge of SCL. Whenever the master generates a Z1 token, it stores SDA. The slave appears to assert its value of SDA for 100 ns after the falling edge of SCL, so we could also use the falling edge of SCL.

Our assembler program runs fine with 987 bytes, but if we add nop instructions to increase to 1003 bytes, and the main loop no longer executes, and we see 1100 samples per second transmitted and received, with oscillating sample values.

[05-DEC-24] We route RESET to TP2 and RCK to TP1. We look at the power-up reset signal, which requires RCK to be running to be cleared. We connect our A3051 directly to our bench-top 3-V power supply.


Figure: Power Up Reset. Yellow: RESET 1 V/div. Green: VA 1 V/div. Blue: RCK 2 V/div. Timebase 10 ms/div.

The source of RCK is an SiT1553, for which the typical power-up time is 150 ms. Our code is running as we expect, with 987 bytes. We pad with NOPs to 1003 bytes. We see the same power-up reset, but code fails, transmitting 1058 SPS and consuming 650 μA. We include a pulse on TP2 = DF1 at the start of the initialization code, but this pulse is never generated. We remove the call to sensor_init, but initialization still does not run. We see pulses on DF0 generated by the interrupt routine. Restore call to sensor_init, pad code to 1067 bytes, still no initialization pulse on DF1. We add a loop at the start of our code that continuously generates a DF1 pulse. Our total code size is 1022 bytes. The loop works, generating the DF1 pulse. Move our initialization routine to the top of our code block, overwriting the loop. On start-up we should see a pulse of 0.3 ms on DF1. Instead the first pulse we see on DF1 is 3 ms, which is the pulse generated by sensor_init. In VHDL set TP2 = DF1, TP1 = (prog_addr=0). Now we see the 0.3-ms pulse on DF1 preceeded by TP1 falling LO. Later, we see the 3-ms pulse on DF1 from sensor initialization. We set TP2 = RESET, making no other changes to the code or software. We see the correct pulses.

We restore our code to the way we want it: a slow write to the control register on the sensor in sensor_init. We pad sensor_init until the total code length is 1003 bytes. We restore the initialize routine to its former position. With TP1 = DF0 and TP2 = DF1 we have the same failure of the code. But if we set TP1 = (prog_addr=0) the code works. We see a start-up pulse on DF1 for boot delay, then for sensor initialization, then repeated pulses for the main loop. We remove prog_cntr from the OSR8 and just use prog_addr. Code fails. We restore prog_cntr. Code fails. We see on TP1 that prog_addr is zero for 5-ns pulses, pulses of 450 ns, and for 60-μs pulses.

We have been jumping U2 with tweezers every time we program. Now we replace U2, but still have the same programming failure at VB = 3.0 V. We increase to VB = 3.3 V and programming is still unreliable. We remove U2 and jumper VA to VB. We reduce our code to 1000 bytes and it runs fine, reading the ID byte and zero, transmitting 128 SPS. Switch to reading TEMP_L and TEMP_H. We are writing 0x38 to IF_CTRL to specify 100 Hz update and averaging 4. Get zeros from these two registers. Current consumption is 263 μA. We try reading P_L and P_H for the pressure measurement. Still all zeros. Write 0x00 to IF_CTRL to return to one-shot mode. Go back to reading ID byte. Current drops to 156 μA and we see the 0xB4 (decimal 180) ID byte. Add three NOPs to the sensor_init routine, bringing code size up to 1003 bytes. Now see no startup pulses, but 600 SPS. We replace the logic chip, U4. Program with 1003-byte code, see same failure. Remove NOPs, size now 1000 bytes. Program, works as before. At 60°C current consumption is 360 μA. At −40 °C, 80 μA. At room temperature 160 μA.

We failed to save waveforms of prog_addr=0 and DF1 hen the code works. But we recall that we get a period of prog_addr<>0 lasting at least a few milliseconds before we see a pulse on TP1 indicating prog-addr=0, then we have our boot pulse on TP2 = DF1. The period of prog_addr<>0 is not correct: prog_addr should be zero all the way until the CPU starts to run. For some reason, prog_addr is not zero when RESET is unasserted. The period when it is not zero and then works could be because prog_addr is reset to address 1001, 1002, or 1003. If the locations 1001 and above are all zero, the processor proceeds through the entire program memory until it gets back to zero, then the program starts. The CPU would take 90 ms to go through 3000 NOP instructions at 33 kHz.