- 29/07/2019 at 08:41 #5413
Dear Programming Guru’s,
I am trying to do a very basic project involving SPI in order to learn how SPI works. I wish to establish communication between two PIC microcontrollers. I have a PIC24FJ64GB002 uC which is going to be set as the master and a dsPIC33FJ128MC802 which will be set as the slave. Each uC is connected in hardware and each is connected to an independent LCD, as seen in the photograph in the attached folder. The principle of operation is very simple: The slave will count up every second and display on an LCD. The slave should then send this counting data over SPI to the master. The master should receive this data and display the received data on the LCD.
The program is KINDA working, in that I believe that the data is being sent to the master – it just isn’t displaying properly on the master LCD.
Could you guys help me fix it? I’m pretty sure that I’ve made some rookie errors along the way, and I’m hoping that this program might provide me with an opportunity to learn more about SPI communication between PIC’s.
Thanks very much!!!
Attachments:You must be logged in to view attached files.
- 29/07/2019 at 08:42 #5415
<div class=”postbody”>Aside from the above mentioned debug question – I am curious about the following:
1. How does the slave device know that it should be talking to the Master PIC? I have mapped the _SS1IN and _SS1OUT pins on the programs, but what actually sets them high? The reason that I ask, is that the end goal fro this project will be to connect FOUR slave PIC devices to a Master PIC device – How will the master know which device is which?
2. I am running the system off the internal FRC and have disabled the primary and secondary oscillator. With advanced init you set the prescalars for primary and secondary oscillators, but I have disabled them. How does the SPI know what frequency to operate at? I’m assuming that it will just take the Fosc as the CLK, but I’m not sure. The origin of my curiosity begins with the fact that when it comes to UART – one must specify the baud rate (eg UART1 Init (9600)), with I2C one must specify the frequency of transmission (eg. I2C1_Init(100000))… With SPI, it’s just SPI1_Init();? It’s a little confusing.
3. Can I run four slaves with one master? In the dsPIC MikroC help file, I only see slave select options from 1 to 3… What happens if you have four devices?
Please excuse my naivety. This is the first time I’m attempting to program SPI. But I really do appreciate the guidance.</div>
<br clear=”all” />
- 30/07/2019 at 01:25 #5417
Hi, There are some few problems I noted in your code:
- You are not pulling down the slave chip select pin of the slave, that indicates to the the slave that the master wants to start a data exchange between itself and the master. The signal is often active low, so a low on this line will indicate the SPI bus is active and communication can take place.
- You have set your SPI communication to 8-bit mode, that’s what your master is expecting , to Reads one byte from the SPI bus. But in your slave you are sending an integer value which is a 32-bit. You need to send a single character, that’s a byte not an integer number. I can’t see the LCD image clearly of the master, so I don’t know what it is displaying , but if I follow your slave code, you are starting with i=0 then increment it by 1, when the slave sends: 0, this in Ascii chart will represent NULL that’s what the master will receive, the same applies to the first 32 characters of ASCII table are not visible characters only from 33 you can start seeing some visible characters. On your slave it shows 51, if all is working well it should have displayed 3 on the master.
- So don’t send an integer, send a byte
- The delays on the receiving side is it necessary?
- Please watch this tutorial even if it uses MPLAB XC8, it explains the basics of SPI how a master can communicate with slaves: https://youtu.be/Y1uPY_9UVPY
- 30/07/2019 at 01:45 #5418
About your questions:
- The slaves knows that it should communicate with the master when its chip select pin goes low: that indicates to the the slave that the master wants to start a data exchange between itself and the master. The signal is often active low, so a low on this line will indicate the SPI bus is active and communication can take place. Please watch this video it explains all in details with one master communicating with three slaves: https://youtu.be/Y1uPY_9UVPY
- You are disabling the scaling, so I believe it will use the Fosc. In this application, why not use the simple SPI1_Init(); to initialize your SPI with defaults settings? I don’t see the need to use the advanced routine which is necessary to specify those features you are disabling.
- Yes you can run multiple slaves with one master, even more than 4. Just connect them correctly, any digital output pin of the master can be used for slave select pin and connected to the dedicated or PPS chip select pin of slave. Your wiring must be correct for it to work. Please watch that video for more info on wiring.
- SPI communication is basically like a ship register, when one bit is shifted to the right another is pushed to replace it, so it doesn’t mater if you are sending or receiving because even if you send, you also receive even if you can just ignore whatever you received if you don’t need it.
- 07/08/2019 at 18:45 #5436
Thank you Bithawa, I watched the video and have a more thorough understanding of SPI communication. I have adapted the code to work for my specific project that I am currently working on and I have the attached code to try to get to work to my preference, but it’s still not working in the way I need the code to work.
I simplified the master and slave code down to what is needed for SPI communication, using the sensor. I have also set both uC clocks to 8MHz internal FRC, to make sure that there are no clock issues. Here is the current dilemma:
In the slave code, when the function
is outside of the while(1) loop; everything works well. Both the slave and the master LCD display the same number, which means that the whole array has been successfully transferred from the slave to the master. If I press the MCLR button, both LCD’s update their values and the values are the same, and these values are correct.
AS SOON AS I put the temp_Array_Calculations(); function into the while(1) loop in order to get the values to update automatically without having to press MCLR; everything goes haywire and the master LCD displays complete garbage?
I think it’s a timing issue. But then again, I’m no master.
Any ideas on how to get this working?
I’m certain that this is a rookie error that can probably be fixed quite easily and I feel that we are very close to a solution.
I received the following message from Filip at MikroC
It’s most likely the fact that you have no handshake between these two MCUs. Both of them are just sending and reading all the time, which I believe causes the corrupt data.
Either implement some sort of handshake, a specific byte that will slave send when its temperature data is ready, which master will keep polling in its while loop, or simply use SPI interrupt.
This does make sense, but would you perhaps know how to implement something like this?
I’m a bit nervous to use interrupts, as they might affect the future routines that will be added to the master code. Is there any other way to establish a digital handshake?
Please see attached – and thank you for the wonderful content and all of the help!
Attachments:You must be logged in to view attached files.
- 14/08/2019 at 02:41 #5447
Hi, Sorry for the late reply I was quite busy recently.
First of all I am not sure which code you are currently testing on, because the code you emailed me is quite different to the code you have attached here.
In the code you have emailed, I picked up some few issues that could cause problems.
1: The Master PIC is set for 0.000010 MHz, this does not seem correct as the slave frequency is quite high.
2: In the Master: LATB.RB4 = 1; I assume this is your chip select pin, it’s always good to write comments so the next guy can know what you are trying to implement. As standard, I would expect to set this pin low when trying to initiate communication with the slave.
3: In the slave:
if (PORTB.RB6 == 1)
for (counter = 0 ; counter < 18 ; counter++)
I assume again PORTB.B6 is the slave, this should be checked for low again and in your SPI1_Init_Advanced() you are disabling the slave SS pin, so I guess this won’t have any effect but how are you going to use it with multiple slaves?
In the code you have attached above, looks better than the emailed one.
Here is a problem that you are probably facing with synchronization. Remember SPI is a two way communication, when the master initiate communication, it sends data to slave which in turns sends data to master whether master/slave will discard data, it doesn’t matter. So once communication starts, master and slave will remain in sych with the master clock pulse as long as the master and slave distance are within the allowed distance (capacitance) as SPI is not meant for long distance communication. So they shouldn’t be any synchronization issue.
Now imagine this scenario: Even if you configure the 2 PICs with same osc frequency, in the master code after initialization which should be fast, it goes straight into the while (1) loop, after 10us, it starts reading from the slave whether the slave has data or not, whether the slave is also busy sending on not. What you might receive cannot be predicted.
In the slave after initialization of various peripherals, SPI, I2C , and if you were to read some I2C sensors, all these could create further delays before slave could start sending data. You are assuming in 10us the slave should have finished everything and be ready to start transmitting, that why you said when data is sent outside the while(1) it seems working, this because maybe it start sending before doing other stuff in the loop.
That is why you were advised some kind of handshaking or interrupts.
You could try increasing your master delay to a very long delay just for testing and see if you could get something to isolate this problem.
I don’t know why you don’t want to use interrupts but in this scenario, interrupts could make your life easy.
The microcontroller needs to receive data at some point, so it has to read and write the SPI signals. Now since you can’t have the microcontroller constantly busy doing this, even your master code now looks simple but when you add more slaves and I assume the master will have to interpret the data received from slaves than process it and do something, all these will take some time to finish while maybe slaves are also busy or already sending data to master, you could get out of sych very quick. Microcontrollers sometimes are equipped with a hardware module solely responsible for the SPI communications. This allows the microcontroller to work on other stuff instead of handling SPI.
While the master can force communication with the slave, that communication may not be fruitful when the slave is doing something else like for example reading sensors as in your case, a forced read can interrupt an on-going read and return either corrupt data or (more likely) old data
The interrupt is raised by the SPI module and it is used to notify the microcontroller that a byte (or more) was received and it is ready for processing.
If you don’t want to use interrupts, you could create a simple kind of handshake with another extra wire per slave for example: when a slave1 is ready to send to master, it can set a certain pin high for example, this pin could be connected to input pins of the master. And set it low when not ready while doing some other stuffs.
when the master is also ready to read data from the slave, it can start polling this input (if more slaves are used, polls all the inputs) for a high (or a low depending on how it is connected, you could also use a pullup resistor). If a ready signal is detected, the master can start reading, as every transaction involves a simultaneous transmission and reception of one byte. It doesn’t matter if you are writing or reading, every single transaction involves sending a byte and receiving a byte at the same time, although often one side or the other is discarding bytes it doesn’t want.
- You must be logged in to reply to this topic.