How to get the LAN9303 into I2C managed mode

In order to set the LAN9303 into I2C managed mode where you can configure the chip using I2C,  strap MNGT1 to 1 and strap MNGT0 to 0. Since the MNGT[1:0] strap pins have an internal pull-up, you only need to strap MNGT0 (pin 26 on the QFN package) to GND using a 10kΩ resistor from this pin to GND.

Posted by Uli Köhler in Electronics, Embedded, Networking

How to access LAN9303 registers over I2C using Arduino / PlatformIO

The LAN9303 has some peculiarities when accessing its registers. This post will not cover indirect register access but only access to the registers which are directly accessible over I2C. Note that the prerequisite for this is to configure the LAN9303 into a mode where management over the I2C slave interface is enabled. See How to get the LAN9303 into I2C managed mode for more info on how to do that.

The main point to take away is that you do not write the register offset from the datasheet (such as 0x50 for the Chip ID and revision register) in the I2C address byte but the address divided by 4 (0x50 >> 2 == 0x14). This is evidenced by figure 8-8 from the datasheet, copyright Microchip, listing the address byte as A[9:2] as opposed to the standard A[7:0]:

 

Example on how to access the register at offset 0x50 (Chip ID and revision register) in Arduino using the Wire library:

const uint8_t LAN9303_I2C_ADDRESS = 0b1010;
const uint16_t LAN9303_CHIPID_REV_Register = 0x50;

Wire.beginTransmission(LAN9303_I2C_ADDRESS);
Wire.write(LAN9303_CHIPID_REV_Register >> 2);
Wire.endTransmission();
Wire.requestFrom(LAN9303_I2C_ADDRESS, 4); // This register is 32 bits = 4 bytes long
delay(5); // Wait for data to be available

// Read directly into an uint8_t
uint32_t buf;
size_t actually_read = Wire.readBytes((uint8_t*)&buf, 4);
// Check if we have received all 4 bytes
if(actually_read != 4) {
    Serial.println("Did not read enough bytes");
}

// Print register value
Serial.printf("LAN9303 Chip ID and revision: %08lx\r\n", __builtin_bswap32(buf));

This will print

LAN9303 Chip ID and revision: 93030001

in other words: Chip ID = 0x9303, revision = 0x0001

 

Posted by Uli Köhler in Arduino, C/C++, Electronics, Embedded, Networking, PlatformIO

How to print 64-bit uint64_t as sixteen hex digits in Arduino

When using Arduino, you often want to print the hex value of a 64-bit value such as a uint64_t, consisting of sixteen hex digits. For example, if you have uint64_t val = 169557370125;, you intend to print 000000277a68250d.

In Arduino you can do that using Serial.printf() with %08lx08lx as format specifier, splitting the uint64_t in two uint32_t instances and printing those one after another:

Serial.printf("%08lx%08lx\r\n",
    ((uint32_t)((val >> 32) & 0xFFFFFFFF)),
    ((uint32_t)(val & 0xFFFFFFFF)));

 

See How to print 32-bit uint32_t as eight hex digits in Arduino for more information on what %x means and why we need to use the 08 in %08x as a printf format specifier.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How to print 32-bit uint32_t as eight hex digits in Arduino

When using Arduino, you often want to print the hex value of a 32-bit value such as a uint32_t, consisting of eight hex digits. For example, if you have uint32_t val = 9177025;, you intend to print 008C07C1.

In Arduino you can do that using Serial.printf() with %08lx as format specifier. Furthermore, you typically want to invert the byte order of the uint32_t using __builtin_bswap32()since it’s more inuitive to write the hex value MSB-first (big-endian) while most hardware platforms represent the uint32_t as LSB-first (little-endian):

Serial.printf("val = %08lx\r\n", __builtin_bswap32(val));

When using printf, %x means to format the value as hex whereas l tells printf() that the argument is a long (32 bit) as opposed to an int (16 bit). 08 means to pad the value with 0s up to a length of 8 digits. If you would format 9177025 using just %x, it would print 008C07C1  instead of 008C07C1. This is why you need to use %08lx instead.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How to print 16-bit uint16_t as four hex digits in Arduino

When using Arduino, you often want to print the hex value of a 16-bit value such as a uint16_t, consisting of four hex digits. For example, if you have uint16_t val = 2022;, you intend to print 07E6.

In Arduino you can do that using Serial.printf() with %04x as format specifier.

Furthermore, you typically want to invert the byte order of the uint16_t using __builtin_bswap16()since it’s more inuitive to write the hex value MSB-first (big-endian) while most hardware platforms represent the uint16_t as LSB-first (little-endian):

Serial.printf("val = %04x\r\n", __builtin_bswap16(val));

When using printf, %x means to format the value as hex. 04 means to pad the value with 0s up to a length of 4 digits. If you would format 2022 using just %x, it would print 7E6  instead of 07E5. This is why you need to use %04x instead.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

How to print byte as two hex digits in Arduino

In embedded programming, you often want to print the hex value of a byte, consisting of two hex digits. For example, if you have uint8_t val = 14;, you intend to print 0x0E.

In Arduino you can do that using Serial.printf() with %02x as format specifier:

Serial.printf("val = %02x\r\n", val);

When using printf, %x means to format the value as hex. 02 means to pad the value with 0s up to a length of 2 digits. If you would format 14 using just %x, it would print E  instead of 0E. This is why you need to use %02x.

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

Arduino I2C: Wire.endTransmission() before or after Wire.requestFrom() ?

The correct order to call Wire commands in Arduino is:

Wire.beginTransmission(MY_I2C_ADDR);
Wire.write(addr);
Wire.endTransmission();
Wire.requestFrom(MY_I2C_ADDR, 1); // Request one byte
delay(5); // Wait for data to be available
uint8_t value = Wire.read();

So you call Wire.endTransmission() after Wire.write() and call Wire.requestFrom() directly after Wire.endTransmission()

Posted by Uli Köhler in Arduino, Electronics, Embedded, PlatformIO

What is the LAN9303 I2C slave address?

I experimentally determined that the LAN9303 uses the I2C slave address 0b0001010. This is listed in the datasheet in section 8.5.1.

Posted by Uli Köhler in Electronics, Embedded, Networking

Teensy 4.x Quadrature Encoder minimal example in PlatformIO/Arduino

This example uses PlatformIO and the Teensy-4.x-Quad-Encoder-Library to implement a hardware quadrature encoder on pins 0 and 1. Remember that the teensy will be destroyed if you use 5V encoder signals. You can only use 3.3V signals!

#include <Arduino.h>
#include <QuadEncoder.h>

QuadEncoder encoder(1, 0, 1, 0);

void setup() {
    Serial.begin(115200);
    encoder.setInitConfig();
    encoder.init();
}

void loop() {
    int32_t position = encoder.read();
    // Compute position in mm and print it
    constexpr float mm_per_count = 0.0012;
    float mm = position * mm_per_count;
    Serial.printf("Position: %+3.4f (count %ld)\r\n", mm, position);
    // Print every 50ms
    delay(50);
}
[env:teensy41]
platform = teensy
board = teensy41
framework = arduino
monitor_speed = 115200
lib_deps =
    git+https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library

 

Posted by Uli Köhler in C/C++, Electronics, Embedded, PlatformIO, Teensy

How to add GitHub repository to PlatformIO lib_deps

Use git+https like this:

lib_deps =
    git+https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library

 

Posted by Uli Köhler in Electronics, Embedded, PlatformIO

Which pins on the Teensy 4.1 are 5V-tolerant?

None of the Teensy 4.1 IO pins are 5V tolerant. You can not connect any 5V signals to any of those pins, doing so will severely damage the hardware. You always need to use some kind of level shifter when connecting 5V signals to the Teensy.

Posted by Uli Köhler in Electronics, Teensy

FR4 PCB thermal expansion online calculator

Calculate the thermal expansion in millimeters (mm) of a FR4 PCB in X/Y direction. A typical temperature difference default is 65°C, the difference between 20°C room temperature and the max temperature rating of 85°C parts. The default 13ppm/°C thermal expansion coefficient is from this website.

TechOverflow calculators:
You can enter values with SI suffixes like 12.2m (equivalent to 0.012) or 14k (14000) or 32u (0.000032).
The results are calculated while you type and shown directly below the calculator, so there is no need to press return or click on a Calculate button. Just make sure that all inputs are green by entering valid values.

mm

°C

ppm/°C

Posted by Uli Köhler in Calculators, Electronics, Physics

How to set pin speed/alternate function in STM32 Arduino (PlatformIO)

You can use the STM32 HAL (STM32CubeMX) even when using Arduino as a framework for STM32 boards in PlatformIO:

GPIO_InitTypeDef pinInit = {
  .Pin = GPIO_PIN_8,
  .Mode = GPIO_MODE_AF_PP,
  .Pull = GPIO_NOPULL,
  .Speed = GPIO_SPEED_FREQ_VERY_HIGH,
  .Alternate = GPIO_AF1_TIM1
};
HAL_GPIO_Init(GPIOA, &pinInit);

Use

#include <stm32f4xx_hal_gpio.h>

in order to include the HAL functions.

Posted by Uli Köhler in Arduino, Electronics, PlatformIO, STM32

How to use HAL_GPIO_Init() in modern C++ (STM32)

In modern C++, you can directly initialize structs like a GPIO_InitTypeDef, making the code much prettier and less prone to errors. The following example configures PA8 of a STM32 in alternate function 1 mode (TIM1 output).

GPIO_InitTypeDef pinInit = {
  .Pin = GPIO_PIN_8,
  .Mode = GPIO_MODE_AF_PP,
  .Pull = GPIO_NOPULL,
  .Speed = GPIO_SPEED_FREQ_VERY_HIGH,
  .Alternate = GPIO_AF1_TIM1
};
HAL_GPIO_Init(GPIOA, &pinInit);

As opposed to the old, much more verbose way of doing that:

GPIO_InitTypeDef pinInit;
pinInit.Pin = GPIO_PIN_8;
pinInit.Mode = GPIO_MODE_AF_PP;
pinInit.Pull = GPIO_NOPULL;
pinInit.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
pinInit.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOA, &pinInit);

 

 

Posted by Uli Köhler in C/C++, Electronics, STM32

What are SO1 & SO2 on the DRV8601?

SO1 and SO2 are the outputs of the two current shunt amplifiers on the DRV8601. These are analog outputs and are typically connected to an ADC.

 

Posted by Uli Köhler in Electronics

How I fixed Ubuntu BOINC Invalid client RPC password. Try reinstalling BOINC

Whenever I started boinc-manager after upgrading to Ubuntu 21.10, it couldn’t connect to the BOINC client, stating that:

Invalid client RPC password. Try reinstalling BOINC

This is how I solved it.

First, generate a new RPC password using:

# Generate new RPC password
sudo apt -y install pwgen
pwgen 30 1 | sudo tee /etc/boinc-client/gui_rpc_auth.cfg
# Fix some permissions
sudo chown root:boinc /etc/boinc-client/gui_rpc_auth.cfg
sudo chown root:boinc /var/lib/boinc/gui_rpc_auth.cfg
# Add current user to BOINC group
sudo usermod -a -G boinc $USER
# Restart BOINC client
sudo systemctl restart boinc-client

After that, retry restarting boincmgrIf the error still persists, reboot and retry!

Posted by Uli Köhler in Linux

What does the ~ (tilde) mean for pins like “~RESET”?

The ~ in pins names like ~RST means not.

  • A pin named without ~, for example RST or RESET, will perform its function (e.g. reset the device) when it is connected to VCC
  • A pin named with ~, for example ~RST or ~RESET, will perform its function (e.g. reset the device) when it is connected to GND

~RESET has exactly the same meaning as overlining the name – for example \overline{\text{RESET}}. Some manufacturers also use use n instead of ~RESET or \overline{\text{RESET}}

Posted by Uli Köhler in Electronics

What does the “n” mean for pins like “nRST”?

The n in pins names like nRST means not.

  • A pin named without n, for example RST or RESET, will perform its function (e.g. reset the device) when it is connected to VCC
  • A pin named with n, for example nRST or nRESET, will perform its function (e.g. reset the device) when it is connected to GND

nRESET has exactly the same meaning as overlining the name. For example \overline{\text{RESET}}. Some manufacturers prefer to use n instead of \overline{\text{RESET}} or ~RESET

Posted by Uli Köhler in Electronics

SN74LV245A as level shifter: How to use the ~OE pin

The ~OE pin on the SN74LV245A defines whether to enable the outputs on the chip. Which pins are inputs and which are outputs is defined by the DIR pins, see SN74LV245A as level shifter: How to use DIR pin for more information.

  • If ~OE is low (i.e. connected to GND), all output pins are enabled
  • If ~OE is high (i.e. connected to Vcc), all output pins are disabled

Note that there is no way to disable individual output pins for the SN74LV245A. You can only enable or disable all the pins together.

In most applications as a level shifter, you want to always enable the output: In order to do that, connect the ~OE pin to GND.

Posted by Uli Köhler in Electronics, Embedded

SN74LV245A as level shifter: How to use the DIR pin

The DIR pin on the SN74LV245A defines whether the A pins or the B pins are the input pins.

  • If DIR is low (i.e. connected to GND), all B pins are inputs and all A pins are outputs.
  • If DIR is high (i.e. connected to Vcc), all A pins are inputs and all B pins are outputs.
Posted by Uli Köhler in Electronics, Embedded
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPTPrivacy &amp; Cookies Policy