Using the 18 bits MCP3421 I2C ADC with Arduino.

A while ago, I published a post about expanding the ESP8266 ADC capacities with the PCF8591 8 bits I2C ADC multiplexer. 8 Bits is really enough for most work I would guess, but if you need more accuracy, say 18 bits for a  high precision Digital Voltmeter, there is the (relatively expensive) MCP3421. I say ‘relatively coz it is still cheaper (and easier to use)  than the LTC2400 (controlled by SPI). This is only a one channel chip, so if you want more channels, you would think you have to get more (which is OK as generally they are sold in webstores in a lot of say 5 or 10), but the chip has no address selection. It has a fixed address of 0x68.
If you do not like soldering though, there is also an ‘evaluation module’ available.

The MCP3421 has an in-program sample rate selection from 12-18 bits and in inbuild Programmable Gain Amplifier that can also be controlled from  your program. There is a library available, several in fact which makes using the chip very easy. If one channel is not enough, try the MCP3424 18-bit, 4-channel, multi-address ADC

Advertisements

Arduino Watchdog timer

I will not go too much into the benefits of a Watchdog timer as I presume those are known, but in short a Watchdog timer resets a processor  when it hasn’t seen any activity of that processor for a while. This is  specifically handy for processors  that are in a less accessible space, where otherwise you’d have to go to, get access and  press reset.

Basically there are 2 types of  Watchdog timers: Hardware and Software. About Software WDT’s I can be brief, they work, but  as the very goal of a WDT is to reset in case of software failure, using a software WDT seems a bit counterintuitive. If however you opt for a software timer, you will find a good article here.

Many of the Atmel chips, such as theAtmega328 in the Arduino UNO have an internal hardware Watchdog timer. In reality that watchdog timer is just a simple counter that gives a pulse when it counts up. This pulse can be used either to generate interrupt or simply reset MCU (or both). The watchdog timer can be reset to zero at any time with the WDR command.

The Internal Watchdog timer of the Atmeag328 is set by by programming WDTON fuse when flashing the MCU. You will find more information here.

Other than having to set fuses when flashing your chip, this internal hardware timer has a drawback similar to the software WDT: If you make a mistake, your chip could get into near continuous reset which makes it hard to re-use it again.

From that point of view an External Hardware WDT might be a better option. If you dont need it anymore, or made a mistake, you simply disconnect it.
There are specific  WDT chips available, but the good old NE555 can be used as well.

Watchdog timer
Watchdog timer

The workings are as follows:
In this circuit the 555 is configured as an astable oscillator. When free running it will charge C2 till about 2/3rds of Vcc (so about 3.33V) and then generate a negative pulse on pin 3 that is connected to the RST of the Arduino (or other chip). Diode D1 is not essential, but it does protect the Arduino.
The frequency, and thus period of the oscillator is determined by R2, R3 and C2. In its current config the time period til reset is about 69 seconds. At the end of that period the  circuit will generate a LOW pulse that  will reset the attached microprocessor. As the dutycycle of the circuit is far from symmetrical (fortunately) the LOW pulse will take some 15 mSec which is a useful time. Not too short, not too long.

However, we do not want the processor to restart every 69 seconds, we just want it ro  do its thing unless it hangs and therefore we let the processor restart the  555 oscillator continuously to signal that it is still alive and kicking. We do that by discharging C2 via R1 and we do that simply by using an output pin that we make LOW. So if during each loop of the firmware in the processor we pull that Output pin LOW, the Watchdog knows the processor is still doing its work and only when the program hangs, the watchdog will do a reset after 69 seconds.

It is not sufficient to just make the Output pin LOW to restart the timer, but afterwards it needs to be set HIGH again. However, even if an output pin is HIGH, there still is an internal impedance that could drain C2. Therefore after setting it as OUTPUT and LOW, we set it back to INPUT mode again, because as input the I/O pins of the Arduino have a fairly high impedance.

R1 limits the current that can flow through the sinking pin to abt 9mA (in reality some 6mA). Ofcourse R1 adds to the  time needed to discharge C2, but that does not pose a problem here. (If not given enough time though, the Watchdog will need less than 69 seconds before it is able to send a reset signal again.)

int HeartbeatPin = 8;

void heartbeat() {
// Sink current to drain C2
pinMode(HeartbeatPin, OUTPUT);
digitalWrite(HeartbeatPin, LOW);
delay(300);
// Set pin back to High Impedance
pinMode(HeartbeatPin, INPUT);
}

void setup() {
// Send an initial heartbeat.
heartbeat();
}

void loop() {
//your code
heartbeat();
}

The above is just a very simple example. Ofcourse it is also possible to check specific sections of the program such as say succeeding an internetconnection or  attaching to a serial port. That way you could avoid  that only part of the program (e.g. connecting to internet)  failed, while the processor is still happily kicking the dog on every loop
The end result however will always be a total reset

Reverse polarity protection with a P-MOSFET

Reverse voltage protection with P-FET
Reverse voltage protection with P-FET

Reverse polarity protection can easily be done with a single diode. The problem with that however is the voltage drop (usually 600mV) that with  large currents can mean a substantial powerdissipation. Using a Skottky diode for its smaller voltage drop is risky as the reverse current through a Skottky is not negligable.
A better way is to use a P-MOSFET as shown in the circuit above. This method is explained very well  in an Afroman youtube video.
Though the direction of the P-Fet may seem a bit counterintuitive, but realise that when the Vgs is in conductive range, the FET will  basically operate as a Switch or in fact a  resistor with very low resistive value, allowing current in both directions.
However you need to pick a FET with low VGS(threshold) so that the device is still offering a tiny volt drop at low battery voltages AND you’ll need a FET with low RDS(on) so that at  your peak current  the FET is dropping less than say 100mV. Other than the FQP4706 the DMG3415U may be a good pick. With 1.8V gate drive it has 0.071Ω resistance.

Switching a humidity sensor off and on

Gardeners who use a resistive moisture sensor to measure the moisture of the soil, sooner or later get faced with corrosion of their metal sensor. Though practically all metals corrode in the soil, in this case it is sped up by the fact that a current flows through the sensor, causing electrolysis.

Several solutions are suggested to solve that like: ‘you have to feed them with AC’ but those solutions are not always practical.

There is however a fairly simple method to minimize the electrolysis and that is to switch off current through the sensor when you do not need it.
Moist soils do not need constant measuring, maybe 3-4 times a day is enough, so if you switch off the sensor except for the say 3x a milisecond or so that makes a big difference.

Easiest might be to use an I/O pin to feed the sensor, but not everybody feels comfortable doing that and not all microcontrollers are suitable for that (although the arduino probably is with 40mA per pin).

But it is in fact quite easy to use a transistor -controlled by an I/O pin- to switch the sensor on and off. Figure 1 gives an example of how to do that with either low side switching or high side switching.

Figure 1a is a very basic transistor switch: Pull the base of the transistor HIGH and current will flow through the sensor, pull it LOW and the current will be switched off. Remember there will be a slight voltage drop (say 250-450 mVolt) over the transistor.

Fig 1b is also a rather basic transistor configuration, it is the emitter-follower or common collector that is often used in voltage buffering. Here also a LOW on the base will switch the transistor OFF and a HIGH will switch it on. Also here one has to take a voltage drop into account (basically the voltage on the I/O pin minus 0.6 Volt). Mind you that Fig 1&2 just give a basic circuit. You’ll need to add a base resistor and possibly a pull-down or pull-up  resistor, depending on  what state you want the circuit to start in.

Figure 2 shows two other circuits you may be considering to try, but that’s not necessarily a good idea.
Fig 2A is basically identical to Fig 1A, but with the sensor and series resistor switched position in the voltage divider.
That does not work because even when the transistor is switched off, there still could be a current flowing through the sensor via the internal impedance of the microcontroller input.
Figure 2B shows a PNP transistor used. That should work right? After all it is basically figure 1A but then reversed in polarity. Well, it is not that simple. The I/O pin is tied to a microcontroller running at say 5V, so its voltage level will vary between 0 and a bit less than 5 Volt. At best it might be 4.2 Volt.*

To keep the PNP transistor switched off, we need to keep the base voltage at nearly the same level as that “+” line and that is hard  in this configuration. Therefore opening the transistor is not a problem, but closing it might, although it will ‘probably’ work

Mind you that Fig 1 and 2 just give a basic circuit. You’ll need to add a base resistor and possibly a pull-down or pull-up  resistor, depending on  what state you want the circuit to start in.

*A pFET on the other hand is quite suitable for high side switching

 

 

JSON, MQTT, PubSub and OpenHAB

Usually I communicate between my various nodes (arduino, esp8266) with MQTT and OpenHAB being the interface. Simple, just one string command per message. Now there comes a moment that it seems better or more convenient, to send more commands in one MQTT message, and that is where JSON comes in. JSON messages are basically an organized string and MQTT is good in sending strings.
Author of the Pubsub library Nick O’Leary’s advice on sending JSON’s is as follows:

However, you need a few tricks before you can send a string variable.

I started off by using the ArduinoJson library to make my JSON’s, but I was not quite happy with that. There are various ways to do it and you end up with some sort of data/char array.

Supposedly you could send that with "client.publish(topic, (char*) payload.c_str())". But for various reasons that didnt suit me so I used another method.

As I was a bit unhappy about adding the ArduinoJson library just to make a JSON string, I thought it would be  best to simply compile the string myself and send that. I am not saying there is no better way… and if there is, please do tell, but this worked for me.

Anyway, let’s start with something simple, I have a LiPo battery feeding an ESP8266 and in openHAB I like to keep track of the voltage of the battery, but I also like to display the Percentage of the battery charged. Ofcourse I can calculate the latter in OpenHAB, but i prefer to have the ESP8266 do that.
Note: the below calculation is for a Wemos D1, with a 100k  resistor  in series with A0. Together with the  residing voltage divider it makes a 100k/(100k+220k+100k) = 1/4.2 voltage divider,  reducing a 4.2Volt voltage to 1 Volt. Therefore a reading of 1023 (=1V) on the A0 port correlates with 4.2 Volt on the LiPo battery)

voltage=analogRead(A0);// (mind you, this is 1 V max)
voltage=voltage/1023.0;// so 1V max renders "1" here
voltage=voltage*4.2;// We want a max of 4.2, so multiply
percent=100*voltage/4.2;// and calculate percentage

The JSON string I need to make, will look as follows

{"Voltage": voltage_value,"Percent": percent_value}

to insert a quote in a string you need to use the backslash as an escape character, so, we make the JSON string as follows:

String payload="{\"Voltage\":"+String(voltage)+ ",\"Percent\":"+String(percent)+"} ";

So now we have the Stringvariable “payload” that we have to send via PubSub.

There may be various ways to do that, I did it as follows:

payload.toCharArray(data, (payload.length() + 1));
client.publish("home/battery",data);

You could probably also use: client.publish("home/battery", payload.c_str());, but I didn’t*).
So, once in openHAB it is quite easy to process the the JSON, once the proper transformation Add-on is installed.

In the items file it then looks like this:

Number battery_garden "Battery Garden [%.1f V]"  (Back_Garden, batteries) {mqtt="<[mosquitto:home/battery:state:JSONPATH($.Voltage)]"}
Number battery_garden_pct "Battery Garden [%.0f %%]"  (Back_Garden, batteries) {mqtt="<[mosquitto:home/battery:state:JSONPATH($.Percent)]"}

And on screen like this:

OK, let’s try that with the reading results of a DHT11. Sure, there might be many reasons why you would want to send the humidity reading and temperature reasing as two different MQTT strings, but for arguments sake let’ s try it as a JSON.

We will first read the DHT11 sensor,then we will create a JSON that looks like {“Temperature”: 20.0, “Humidity”: 68}  with 20.0 and 68 of course just snapshot  examples. Subsequently we will create the MQTT message and display it in openHAB

float humid_coop = dht.readHumidity();
float temp_coop = dht.readTemperature();
String payload="{\"Humidity\":"+String(humid_coop)+ ",\"Temperature\":"+String(temp_coop)+"} ";
payload.toCharArray(data, (payload.length() + 1));
client.publish("home/coop", data);

and then in the itemsfile:

Number Humidity_Coop "Humidity Coop [%.0f %%]" (coop) {mqtt="<[mosquitto:home/coop:state:JSONPATH($.Humidity)]"}
and
Number Temperature_coop "Temperatuur [%.2f °C]" (coop) {mqtt="<[mosquitto:home/coop:state:JSONPATH($.Temperature)]"}

Let’s now have a look at sending more than just two data  values. Suppose you have an I/O chip (or more) that lets you read 12 channels at the same time, you could ofcourse make a JSON like this: {“channel1” : value1, “channel2″:value2,  ……..”channel12”: value12}, but that seems to send a lot of unnecessary data, so we will create the following JSON:

{"data":[value1,.............value12]}
We do that as follows

String payload="{\"data\":["+String(ana0)+","+String(ana1)+","+String(ana2)+","+String(ana3)+","+String(ana4)+","+String(ana5)+","+String(ana6)+","+String(ana7)+","+String(ana8)+","+String(ana9)+","+String(ana10)+","+String(ana11)+ "]}";
payload.toCharArray(data, (payload.length() + 1));
client.publish("home/json", data);

in the MQTT channel in the items file we will now use a slightly different JSON format. The data will now be read by index number like:

JSONPATH($.data[0])

the full itemsfile then will be

Number Moisture1 "Moisture 1 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[0])]"}
Number Moisture2 "Moisture 2 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[1])]"}
Number Moisture3 "Moisture 3 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[2])]"}
Number Moisture4 "Moisture 4 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[3])]"}
Number Moisture5 "Moisture 5 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[4])]"}
Number Moisture6 "Moisture 6 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[5])]"}
Number Moisture7 "Moisture 7 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[6])]"}
Number Moisture8 "Moisture 8 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[7])]"}
Number Moisture9 "Moisture 9 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[8])]"}
Number Moisture10 "Moisture 10 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[9])]"}
Number Moisture11 "Moisture 11 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[10])]"}
Number Moisture12 "Moisture 12 [%.0f]" <plantbed> (Garden_moist) {mqtt="<[mosquitto:home/json:state:JSONPATH($.data[11])]"}

and look like:

There is nothing stopping you from including data from more than 1 sensor in a JSON and send that all in one MQTT message. This way you could for instance put all the sensor data from say one room, or the entire garden in one MQTT message and send it.
Beware though that the default packet size supported by the PubSub client is 128 bytes. You can increase this limit by editing the value of MQTT_MAX_PACKET_SIZE in PubSubClient.h.
___________________
*)There is a fork of Nick O’Leary’s PubSub library, by Imroy, that will happily send:
client.publish(topic, String (value));

The LM335 and it’s serieresistor

alibrated mode
Fig 1: LM335 in Calibrated mode

The LM335 belongs to a range of a fairly accurate and simple to use temperature sensors.

The LM335 operates from -40°C to 100°C. It’s output is lineair with 10mV/°Kelvin (¶ 6.6 in the datasheet). It can be used in two ways: Calibrated and uncalibrated mode. The difference is a  10kΩ potentiometer that is used to regulate the output voltage to 2.98 Volt at 25°C (25°Celsius is 298.15°Kelvin) . With more and more devices running off of 3.3 Volt, the question is sometimes raised: will the LM335 run off of 3.3 Volt as well. Going through the datasheet you will not see a min or max value stated for the voltage to be used as all depends on the current through the LM335 and that current is determined by a series resistor (R1 in Fig. 1)

If we want to use the calibrated configuration of the LM335 then this is how to calculate the series resistor for the LM335:
According to the datasheet, the potentiometer needs to set the voltage over the LM335 at 2.98 Volts at  25°C (¶ 6.4 in the datasheet). The LM335 needs between 400uA and 5 mA (¶ 6.2 in the datasheet). Suppose that the max temperature we want to measure is 30 C (=303.15 °K). The output then will be 3.0315 Volt (let’s say 3.03 V).
At 3.03V the current through the 10k potentiometer will be 3.03/10k=303uA. The minimum current that needs to flow through the LM335 is 400uA, so R1 needs to supply 703uA over a voltage of Vcc-3.03V.

So at 5 Volt that would be 1.97/0.703 = 2.8kΩ
At 3.3 Volt it would be 0.27/0.703 = 0.384kOhm =384Ω
(Note 703uA= 0.703mA = 0.000703A. I chose to divide by mA so I get outcome in kΩ).
Now we still have to check if the current will not be too high at the lowest temperature we want to measure:
Let’s say our minimum temperature is 0°C that is 273.15. At 10mV/°K that means an output voltage of 2.73 Volt.
At 5 Volt the resistor current will be (5-2.73)/2.8kΩ = 810uA. We still need to subtract 2.73V/10kOhm=273uA which flows through the potentiometer so we have 810-273=537uA, which is well below the 5mA max.

If we calculate that for 3.3Volt, we find the following:
The resistor current will be (3.3-2.73)/384=1.5mA. Subtract 273uA that flows through the potentiometer and that gives roughly 1.23mA, well within limits.

If you want to measure temperatures higher than 30°C then R1 has to be smaller. When using 3.3 Volt the  theoretical maximum temperature measurable is 330°K which is about 57°C. In practice however that does not work as you need a drop voltage over R1 so the value of R1 cannot be zero, or, in other words: you cannot connect the LM335 directly to Vcc and still expect to get an output lower than Vcc.

Bet let’s see how that would be at 50°C (323.15°K) and 3.3V Vcc :
Well again you need 703uA but this time over 0.07V.
That gives a value  for R1 of 100Ω.
But then at 0 degrees the current is 5.7mA. Still need to subtract 2.73uA which gives 5.4mA which is out of spec.

A program would be as follows:

//A0 is used to read the LM335
void setup()
{
Serial.begin(9600);
}
void loop()
{
int rawvoltage= analogRead(A0);
float millivolts= (rawvoltage/1024.0) * 5000;
float kelvin= (millivolts/10);
Serial.print(kelvin);
Serial.println(" degrees Kelvin");

float celsius= kelvin - 273.15;
Serial.print(celsius);
Serial.println(" degrees Celsius");

float fahrenheit= ((celsius * 9)/5 +32);
Serial.print(fahrenheit);
Serial.println(" degrees Fahrenheit");

delay(2000);
}

Beware though that the ESP8266, in spite of it being a 3V3 device only wants a maximum of 1 Volt on its ADC

The W5100 bug(s) – and how to fix it (them)

Bug 1- The SPI bug

On a recent project in which I shared the SPI bus of a 3V3 8MHz ProMini, with a W5100 Ethernet module and another SPI slave, I experienced some problems: sometimes it would work perfectly, sometimes not.
I had hooked up the ethernetmodule with Pin D10 as Chipselect and the other slave (an RFM69) with Pin D8 as Chipselect. Pretty standard and it should work, shouldnt it?
Well as it is, it didnt. Oddly enough, I had build it before with another Ethernet module and that worked fine.
When I connected my EthernetShield in the same way, the issue was gone. Time to throw suspicion on my Funduino W5100 Ethernetmodule. Well on inspection it is immediately clear that eventhough the functionality is supposed to be the same, the ethernetshield and also my previous module have more chips than my Funduino module. Why for instance does my shield have a 74LVC14 and my Funduino module just the W5100 chip and nothing more?

When looking at the circuit of the Ethernetshield it is clear that only one gate of the 74LVC14 (a SchmittTrigger inverter) is used: it takes the SS signal (the ‘chipselect’) inverts that and sends that inverted signal to Pin 31 of the W5100. Pin 31 is the SEN pin.

In the Funduino module that was different. The ‘SEN’ pin is just tied high to 3V3 with a 10k resistor. My shield has that pull-up resister as well, but still is controlled by the inverted chipselect signal.

Time for the datasheet of the W5100

Hmm.. that doesnt say much, other than that in my module the SPI mode is enabled, however, judging from the 74LVC14, it seems that this pin needs to be driven to LOW when the Chip is not selected. In other words, it is apparently necessary to disable the SPI mode in order to release the bus to another slave.

Time for some soldering: apart from the Vcc and ground, one needs two signals: the SS pin and the SEN pin. As the W5100 is an 80 LQTF chip, at my age (eyes) I was not even going to try soldering on the chip, but fortunately the Pullup resistor gives an entry point to the SEND signal and the connector is where we find the SS signal

Pullup resistor on SEN pin
Pullup resistor on SEN pin
Pullup resistor on SEN pin, close-up
Pullup resistor on SEN pin, close-up

I used a 74LCV14  (Low Voltage Inverting SchmittTrigger) for my modification, but I am sure an 74LC04 or 74LVT04 (an inverter) would do just as well. If you vcannot find the 74LCV14, try a 74LVT14 or 74HC(T)14 (it accepts  2 Volt Vcc). John Crouchley who also describes this problem uses a CMOS CD4011. He feeds that from 5Volt, which I did not want to do. It should be posible though, given the fact that the W5100 pins apear to be 5 V tolerant. Perhaps even a simple 1 transistor inverter is possible. Ideal would be an 74AHC1G04 as that is only a single inverter chip that measures only 2x3mm and can easily find a plce on the module.
Currently my modification is breadboarded. I will think of a neat solution and then add some more pictures.

Bug 2- The ‘510’ bug

There is another problem with some of the ‘asian webstore’ W5100 based Ethernet shields which isnt really a bug with the W5100 but more a problem with bad sourcing.
Some of those shields refuse to make contact with the internet because of some wrong components (resistors)In the picture here of the top of an ethernet shield, directly right of the Ethernet jack there is a “spider” resistor that is labelled with “49R9” that are actually 4 resistors in one  package with each a value of 49.9 Ohm. Apparently that was hrd to source at some time and  clone manufacturers decided to use 51 Ohm resitors. That is not a problem if indeed they had used 51 Ohm, but by mistake 510 ohm resistors were used (labelled ‘511’). Resistors with a value of 51 ohm should have been labelled with ‘510’.
So if you have such a board you need to replace the 510 ohm resistors. If you can’t find the proper replacement resistorpack then apparently it is also OK to solder  a 100 ohm resistor between pin 1-2 (Tx+/Tx-) and a 100 ohm resistor between pin 3 and 6 (Rx+/Rx-) as explained here. (So 2×100 Ohm resistors in total).

rj45
The RJ45 Jack, seen from component side

Bug 3 – The Funduino Reset Bug

Screenshot_2017-04-19_22-53-51The “Funduino” W5100 module as is a cheap, but qualitatively good W5100 board. However, apart from the ‘problem’ of not being able to share the SPI bus in unmodified state (adressed above), some  people have a lot of trouble getting it to work in the first place. The problem is then most likely in the Reset of the module. Modern versions of the Ethernetshield have a seperate Reset controller, that is triggered by the RST of the Arduino. The Funduino Module, just has its RESET tied to 3.3V via a 10 k resistor. As a result the Module’s reset state is a bit unpredictable. Some people get it to work by powering the module up and down a few times, but that remains random luck. What I found that works immediately is to add a slight delay in the setup, before the Ethernet connection is initialized. For me 250mS was enough, but you may need a bit more or a bit less.
So my Setup looks as follows:

void setup() {
// setup ethernet communication using DHCP
delay(250);//

Also, when you use the shield, the Reset pins of the Arduino and the shield are connected, so the Arduino can reset the shield. With this module you cannot do that: if you would connect both resets, you will notice that you cannot upload sketches. Perhaps it will work if you only connect the RST after you upload a sketch, I did not try that, too much hassle. I found the 250mS delay to work for me.
This ‘bug’ does not happen with all Funduino W5100 modules. Supposedly some batches are ‘OK’. There are 2 identification numbers: one on the PCB and one on the RJ45 jack. Supposedly if that says “15/10”  it is OK, “14/10” is not. Mine said “16/38” and needed the delay.
The only conenctions (other than Vcc and ground)  that I make are:
D10  -> nss
D11  -> miso
D12  -> mosi
D13  -> sck