Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible ESP32 SPI Issue with NXP MC33996 #981

Closed
ProtoG opened this issue Jan 8, 2018 · 13 comments
Closed

Possible ESP32 SPI Issue with NXP MC33996 #981

ProtoG opened this issue Jan 8, 2018 · 13 comments

Comments

@ProtoG
Copy link

ProtoG commented Jan 8, 2018

Hardware:

Board: ESP32 Dev Module
Core Installation/update date: 11/jul/2017
IDE name: Arduino IDE
Flash Frequency: 40Mhz
Upload Speed: 115200

Description:I'm using an ESP32 to to trigger 16 outputs with SPI and an NXP MC33996. I made a small breakout board with 16 LEDs(one for each output). My code works fine except output 8 and output 0 are not turning on. They just so happen to be the outputs associated with the last bit of the last two bytes sent to the chip. I've tried turning on one LED on at a time but I still miss output 8 and output 0. There are no shorts on the board and all the LEDs have been tested in circuit. I'm going to try it with a different MCU later just to see if I have the same issue or not.

Any ideas? See the code below:

#include <SPI.h>
#define CSpin 5

/*ESP32 SPI PINOUT MISO 19 MOSI 23 SLK 18 CS 5 */

int dlay = 100;

void setup() {

Serial.begin(115200);

SPI.setClockDivider(SPI_CLOCK_DIV8);

SPI.setDataMode(SPI_MODE1);

SPI.setBitOrder(MSBFIRST);

pinMode(CSpin, OUTPUT);

digitalWrite(CSpin, HIGH);

SPI.begin(); }

void loop() {

Serial.println("ON"); digitalWrite(CSpin, LOW); //select slave

SPI.transfer(0b00000000); //command

SPI.transfer(0b11111111); //first 8 outputs ON

SPI.transfer(0b11111111); //last 8 outputs ON

digitalWrite(CSpin, HIGH); //de-select slave

delay(dlay);

}//end of main

@ProtoG
Copy link
Author

ProtoG commented Jan 8, 2018

Just tried it with an Atmel ATmega168 and it works just fine with the same exact code.

@ProtoG
Copy link
Author

ProtoG commented Jan 9, 2018

Here's a picture of the decoded SPI from the ATmega168: https://imgur.com/6gSDUVF

Here's a picture of the decoded SPI from the ESP32: https://imgur.com/uUXJfRN

They both decode to the same value: 00000000 - 11111111 - 11111111

Which is what the code is instructing them to do but the ATmega seems to keep the MOSI(purple) high between bytes and the ESP32 pulls MOSI low between bytes.

The NXP MC33996 is rated for 6MHz. I've tried SPI @2MHz and @4Mhz with no luck. Any ideas?

@stickbreaker
Copy link
Contributor

@ProtoG were both of these scope images at 2MHz data rate? The reason I ask is that the 168 calcs to 2MHz while the ESP is 4MHZ.

I would zoom in on data bytes and overlay the SCK and MOSI traces. Change your data pattern to 0xA5 (0b10100101) 0x5A (0b01011010)

Verify that the data is stable on the falling edge of SCK. SPI MODE1 samples the values on the falling edge of the clock signal. you will probably have to go down to ns divisions.

Also slow the clock way down, 100KHz, 500KHz etc. I would expect a better waveform. But, your ESP example was at 4MHz. Is this a BreadBoard? or PCB?

Chuck.

@ProtoG
Copy link
Author

ProtoG commented Jan 9, 2018

@stickbreaker The 168 is at 2MHz and the ESP32 is set at 4MHz in the screenshots. I tried the ESP32 at 2MHz as well but same result. I'll try reducing the clock speed even more and yes, it's on a breadboard for both examples.

I'm going to try SPI.transfer32() later to see if that works any better.

@stickbreaker
Copy link
Contributor

@ProtoG 4MHz is fast on a breadboard. I remember the days of 2mhz CPU clocks and 8bit databus's needing termination to function correctly.

Your scope images are showing a lot of crosstalk and ringing/overshoot.

StackExchange has a good thread discussing SPI bus termination issues here: SPI bus termination Considerations

Chuck.

@ProtoG
Copy link
Author

ProtoG commented Jan 9, 2018

@stickbreaker So I just tried a few thing and I managed to consistently pick up the last bit of the second byte but I'm still missing the last bit of the third byte.

Here's a screenshot of my attempt at passing 32bits with SPI.transfer32(): https://imgur.com/WpdEZY7

The NXP MC3396 doesn't seem to like the 32bit transfer and doesn't turn any of the outputs on.

Here's a screenshot of first transferring 8bits with SPI.transfer(0b00000000) and then transferring the 16bits associated with the outputs with SPI.transfer16(0b1111111111111111):
https://imgur.com/8bIeFjw

That works and I can get the last bit of the second byte but I'm still missing the last bit of the third byte.

Here's another screenshot with the same technique at 125kHz: https://imgur.com/YL4Ik8f

Looking back at the ATmega168 screenshot above, the MCU keeps MOSI high even after the clock stops until the chip select pin is pull back high. Is there anyway to do something similar with the ESP32?

I didn't seem to notice a difference between change the SPI mode from 0, 1, 2, or 3. Is that potentially the issue? The NXP MC33996 responds the same with all SPI modes and all outputs but output 0 work fine.

@stickbreaker
Copy link
Contributor

@ProtoG I just reviewed all of your ESP32 scope images, All of them show MODE0. The 168 shows Mode1.
This screen shot (8BIeFjw) is easy to see Mode0: (samplings on Rising Clock). MOSI goes High before SCK. and changes back to Idle at Falling edge of Clock.

8biefjw

This Device is Mode1, the last bit (16) is going to be low when it is sampled, MODE1 samples after the falling edge. The datasheet shows the sample period to be between 16ns and 20ns After the falling edge of SCK is detected. The first byte only works because the MOSI bus idle state is LOW.

recommendation:

Before you spend more time debugging: UPDATE your ESP32 core.

There have been many changes since JULY 2017.

Your posted images all show that the ESP32 is NOT sending MODE1 data, it is always sending MODE0. So, Update to the current version then we can dive into the SPI code to figure out why it is not correctly configuring the hardware.

addition debug steps:

Run the same scope setup with trace 3(MOSI) offset ~1/5 div below trace 1(SCK) decrease voltage to 2V/div remove the decoded(MISO/MOSI The scope is not the issue)
The reason for this increase resolution, I want to see how much overshoot/undershoot is being created at the device.

Have your software try Mode0 then Mode1. Let's see if the ESP32 is actually producing Mode0 and Mode1 correctly. Then we can work through the Device issues.

Can you use 0xA55A and 0x5AA5 as your pattern? (more chances for the error to happen)

Post the Scope capture and the corresponding LED (output) results.

Chuck.

@ProtoG
Copy link
Author

ProtoG commented Jan 10, 2018

@stickbreaker Thanks for the help! The issue was that SPI.setDataMode(SPI_MODE1); must be called after SPI.begin();

The code below now works and it is clearly showing MODE1. The other issue is that I even tried calling SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE1));
in the loop which should work but that did not work either on the ESP32. All 3 cases worked on the ATmega168.

Better yet, it worked at 8MHz even though the NXP MC33996 says max of 6MHz but I'll use it at 4MHz for my project.

ds1z_quickprint99

`
#include <SPI.h>
#define CSpin 5
//#define CONFIG_DISABLE_HAL_LOCKS 1 //increases speed between transfers

/*ESP32 SPI PINOUT
MISO 19 - MOSI 23 - SLK 18 - CS 5
*/

int dlay = 2000;
void setup() {
Serial.begin(115200);
pinMode(CSpin, OUTPUT);
digitalWrite(CSpin, HIGH);

SPI.begin();

SPI.setClockDivider(SPI_CLOCK_DIV4);
SPI.setDataMode(SPI_MODE1);
SPI.setBitOrder(MSBFIRST);

}

void loop() {

digitalWrite(CSpin, LOW); //select slave
SPI.transfer(0b00000000); //command byte
SPI.transfer16(0b0101010101010101); //16 output bits
digitalWrite(CSpin, HIGH); //de-select slave
delay(dlay);

}//end of main`

@ProtoG ProtoG closed this as completed Jan 10, 2018
@stickbreaker
Copy link
Contributor

@ProtoG Great! I'm glad you found your error.

We'll have to note that SPI.beginTransaction(SPISettings(SPI_CLOCK_DIV4, MSBFIRST, SPI_MODE1)); does not correctly configure the hardware.

Are you really using the July 2017 version?

Chuck.

@ProtoG
Copy link
Author

ProtoG commented Jan 10, 2018

@stickbreaker I downloaded and installed the Arduino core for ESP32 in November so yes. Where do I submit the issue?

Thanks again Chuck!

@stickbreaker
Copy link
Contributor

stickbreaker commented Jan 10, 2018

@ProtoG So, you are using a November 2017 core, not a July 2017.

Just create a simple sketch using SPI.beginTransaction() capture the scope output post both sketch and scope image as a new issue, title it something like 'SPI.beginTransaction() doesn't work' 😄

Unless you update to the current core, most people will assume your 'old' core was the problem and ignore it until there are other reports of the same problem happening with the 'current' core.

This ESP32 project is mainly volunteer, I am working on the I2C section because it interests me. I have successfully created a stable MASTER mode Interrupt driven library. I just expanded it to handle both I2C statemachines, now I am working on the SLAVE mode.

If it interests you, you could solve this SPI problem 😁 That could be your Boy Scout daily good Deed!

I currently don't have any SPI devices attached to my ESP32's so, I haven't use the SPI interface.

Chuck.

@ProtoG
Copy link
Author

ProtoG commented Jan 10, 2018

@stickbreaker I'm new here, how do I update to the most recent revision of the core? I tried going through same steps I used to install it in the mac terminal, but I get an error, "fatal: destination path 'esp32' already exists and is not an empty directory."

Also, I went to retest the code I saved with SPI.beginTransaction() and I had it set to MODE0 😔
It does properly set to MODE1, but still when using SPI.setClockDivider(SPI_CLOCK_DIV4); SPI.setDataMode(SPI_MODE1); SPI.setBitOrder(MSBFIRST);

It must be declared after SPI.begin(); and not before.

Thank you for your work on the I2C section! I have plenty of I2C sensors in my part drawers.

@stickbreaker
Copy link
Contributor

I don't know Apple, but under Window all of the ESP32 stuff is load in my Arduino 1.8.5 sketch directory.

in my example

c:\Users\user\My Documents\Arduino\hardware\espressif

So, to do a clean Install of the ESP32 stuff I just delete the espressif directory and everything below it.
Then I can reinstall using the installation instructions.

I would upgrade to Arduino 1.8.5 then upgrade the ESP32 support.

Chuck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants