I'm trying to develop a interface SPI and I have started with a simple configuration.
The question is that SCK seems to work fine but MOSI doesnt works.
Here is my code and my test logical tester.
#include <stdlib.h>
#include <plib.h>
// example functions prototypes
int SpiDoMasterSlaveExample(int nCycles);
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster);
// some definitions
#define MIN_SPI_TXFER_SIZE 8 // min number of words per transfer
#define MAX_SPI_TXFER_SIZE 512 // max number of words per transfer
// configuration settings
#pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
int main(void)
{
SYSTEMConfigPerformance(72000000L);
srand(ReadCoreTimer()); // seed the pseudo random generator
if(!SpiDoMasterSlaveExample(100))
{
return 0; // our example failed
}
return 1;
}
int SpiDoMasterSlaveExample(int nCycles)
{
int fail=0; // overall result
SpiInitDevice(1, 1, 1, 1); // initialize the SPI channel 1 as master, frame master
SpiInitDevice(2, 0, 1, 0); // initialize the SPI channel 2 as slave, frame slave
while(nCycles-- && !fail)
{
unsigned int txferSize;
unsigned short* pTxBuff;
unsigned short* pRxBuff;
txferSize=MIN_SPI_TXFER_SIZE+rand()%(MAX_SPI_TXFER_SIZE-MIN_SPI_TXFER_SIZE+1); // get a random transfer size
pTxBuff=(unsigned short*)malloc(txferSize*sizeof(short));
pRxBuff=(unsigned short*)malloc(txferSize*sizeof(short)); // we'll transfer 16 bits words
if(pTxBuff && pRxBuff)
{
unsigned short* pSrc=pTxBuff;
unsigned short* pDst=pRxBuff;
int ix;
int rdData;
for(ix=0; ix<txferSize; ix++)
{
pTxBuff[ix]='A'; // fill buffer with some random data
}
ix=txferSize+1; // transfer one extra word to give the slave the possibility to reply back the last sent word
while(ix--)
{
SpiChnPutC(1, *pSrc++); // send data on the master channel, SPI1
rdData=SpiChnGetC(1); // get the received data
if(ix!=txferSize)
{ // skip the first received character, it's garbage
*pDst++=rdData; // store the received data
}
rdData=SpiChnGetC(2); // receive data on the slave channel, SPI2
SpiChnPutC(2, rdData); // relay back data
}
// now let's check that the data was received ok
pSrc=pTxBuff;
pDst=pRxBuff;
for(ix=0; ix<txferSize; ix++)
{
if(*pDst++!=*pSrc++)
{
fail=1; // data mismatch
break;
}
}
}
else
{ // memory allocation failed
fail=1;
}
free(pRxBuff);
free(pTxBuff); // free the allocated buffers
}
return !fail;
}
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster)
{
unsigned int config=SPI_CON_MODE16|SPI_CON_SMP|SPI_CON_ON; // SPI configuration word
if(isMaster)
{
config|=SPI_CON_MSTEN;
}
if(frmEn)
{
config|=SPI_CON_FRMEN;
if(!frmMaster)
{
config|=SPI_CON_FRMSYNC;
}
}
SpiChnOpen(chn, config, 4); // divide fpb by 4, configure the I/O ports. Not using SS in this example
}
Sorry, I can't post the logical analyser image for my reputation points.
I'm trying to send "A" all time (fill buffer transmit). That's send data to SPI1.
I'm reading SPI1 from my Microchip Expansion Board I/O where SPI1 is in pins 41 and 43 (41 SCK and 43 SDO).
In SPI2, pin 23 and 25, obviously I have not any traffic.
Does anyone have idea of this error?
Thanks a lot
The PIC32MX series has mapable input and output pins for some peripherals, including the SPI. This means, that MOSI and MISO can be mapped to different pins, depending on your specific needs.
You need to specify this in code before you start using the SPI, otherwise, the PIC won't know which pins to use.
The following is just an example of how to setup the pins (peripheral pin select). You need to look in your PIC's datasheet for the mappings. The first parameter in the calls is the table index from the datasheet.
/* inputs */
PPSInput(2, SDI1, RPF2); // F2, MEMORY MISO -> SPI1SDI
PPSInput(2, SDI2, RPG7); // G7, ZB MISO -> SPI2SDI
/* outputs */
PPSOutput(4, RPF3, SDO1); // F3, MEMORY MOSI -> SPI1SDO
PPSOutput(1, RPG8, SDO2); // G8, ZB MOSI -> SPI2SDO
As described before, check your peripheral pin select. Additional you must set your port direction to Output (PDx-Register). MISO must be set to an Input.
Related
I am trying a lot of days to acomplish a communication via spi (stm32-nrf24..) and it doesn't work despite that I had read a lot of resources I cant make it right and I dont know why this is happening, I realy need help. I have nucleol053r8 and nrf24l01 and I want to accive a communication between them. When I am truing to debug the spi, for example to write something on DR and after to read it, nothing works! It seems that nothing is writing to DR.
My configurations for this communication are
CPOL=CPHA=0
FULL DUPLEX MODE
MSB FIRST
MASTER MODE ON
8bit DATA FRAME
SSM=SSI=1
Here is my functions for reading and writing.
void spi1_transmit(uint8_t *data,uint32_t size){
uint32_t i=0;
uint8_t temp;
while (i<size){
while (!READ_BIT(SPI1->SR,SPI_SR_TXE));
SPI1->DR=data[i];
i++;
}
while (!READ_BIT(SPI1->SR,SPI_SR_TXE));
while (READ_BIT(SPI1->SR,SPI_SR_BSY));
temp = SPI1->DR;
temp = SPI1->SR;
}
void spi1_receive(uint8_t *data,uint32_t size){
while (size){
SPI1->DR=0;
while (!READ_BIT(SPI1->SR,SPI_SR_RXNE));
*data++=(SPI1->DR);
size--;
}
}
void spi1_gpio_init(){
/*Enable clock access to GPIOA*/
SET_BIT(RCC->IOPENR,IOPAEN);
/*Setting as AF functions the proper pins. */
CLEAR_BIT(GPIOA->MODER,(1U<<10)); // PA5
SET_BIT(GPIOA->MODER,(1U<<11));
CLEAR_BIT(GPIOA->OTYPER,(1U<<5));
SET_BIT(GPIOA->OSPEEDR,(1U<<10));
SET_BIT(GPIOA->OSPEEDR,(1U<<11));
// Setting AF type AF0.
CLEAR_BIT(GPIOA->AFR[0],(1U<<20));
CLEAR_BIT(GPIOA->AFR[0],(1U<<21));
CLEAR_BIT(GPIOA->AFR[0],(1U<<22));
CLEAR_BIT(GPIOA->AFR[0],(1U<<23));
CLEAR_BIT(GPIOA->MODER,(1U<<12)); //PA6
SET_BIT(GPIOA->MODER,(1U<<13));
CLEAR_BIT(GPIOA->OTYPER,(1U<<6));
SET_BIT(GPIOA->OSPEEDR,(1U<<12));
SET_BIT(GPIOA->OSPEEDR,(1U<<13));
// Setting AF type AF0.
CLEAR_BIT(GPIOA->AFR[0],(1U<<24));
CLEAR_BIT(GPIOA->AFR[0],(1U<<25));
CLEAR_BIT(GPIOA->AFR[0],(1U<<26));
CLEAR_BIT(GPIOA->AFR[0],(1U<<27));
CLEAR_BIT(GPIOA->MODER,(1U<<14)); //PA7
SET_BIT(GPIOA->MODER,(1U<<15));
CLEAR_BIT(GPIOA->OTYPER,(1U<<7));
SET_BIT(GPIOA->OSPEEDR,(1U<<14));
SET_BIT(GPIOA->OSPEEDR,(1U<<15));
// Setting AF type AF0.
CLEAR_BIT(GPIOA->AFR[0],(1U<<28));
CLEAR_BIT(GPIOA->AFR[0],(1U<<29));
CLEAR_BIT(GPIOA->AFR[0],(1U<<30));
CLEAR_BIT(GPIOA->AFR[0],(1U<<31));
SET_BIT(GPIOA->MODER,(1U<<18)); //PA9
CLEAR_BIT(GPIOA->MODER,(1U<<19));
CLEAR_BIT(GPIOA->OTYPER,(1U<<9));
SET_BIT(GPIOA->OSPEEDR,(1U<<18));
SET_BIT(GPIOA->OSPEEDR,(1U<<19));
SET_BIT(GPIOA->MODER,(1U<<16)); //PA8
CLEAR_BIT(GPIOA->MODER,(1U<<17));
CLEAR_BIT(GPIOA->OTYPER,(1U<<8));
SET_BIT(GPIOA->OSPEEDR,(1U<<16));
SET_BIT(GPIOA->OSPEEDR,(1U<<17));
}
void spi1_config(){
/*Enable clock access to SPI1.*/
SET_BIT(RCC->APB2ENR,SPI1_EN);
/*Setting up BAUDRATE. FPCLK/32 (100) */
SET_BIT(SPI1->CR1,(1U<<5)); // 1.
CLEAR_BIT(SPI1->CR1,(1U<<4)); // 0.
CLEAR_BIT(SPI1->CR1,(1U<<3)); // 0.
/*Setting up CPOL=0 and CPHA=0.*/
CLEAR_BIT(SPI1->CR1,(1U<<0)); // CPHA=0.
CLEAR_BIT(SPI1->CR1,(1U<<1)); // CPOL=0.
/*Enable full-duplex mode.*/
CLEAR_BIT(SPI1->CR1,(1U<<10));
/*Set MSB first.*/
CLEAR_BIT(SPI1->CR1,(1U<<7));
/*Enable Master mode.*/
SET_BIT(SPI1->CR1,(1U<<2));
/*Setting up 8-bit data frame.*/
CLEAR_BIT(SPI1->CR1,(1U<<11));
/*Enable software slave management. SSM=1 and SSI=1.*/
SET_BIT(SPI1->CR1,(1U<<9)); // SSM=1.
SET_BIT(SPI1->CR1,(1U<<8)); // SSI=1.
cs_disable();
ce_disable();
/*Enable SPI peripheral.*/
SET_BIT(SPI1->CR1,(1U<<6));
}
and with this why am testing it
int main(void){
uint8_t tx_b[3],rx_b[3];
init_rcc();
spi1_gpio_init();
spi1_config();
tx_b[0]=0b00111111;
tx_b[1]=0b00001000;
tx_b[2]=0b00101000;
spi1_transmit(tx_b,3);
while(1){
spi1_receive(rx_b,3);
}
}
You need to enable SPI clock
You need to enable the peripheral
Many STM32 SPIs have FIFO and you need to force the compiler to generate the correct size store instructions.
For example
*(volatile uint8_t *)&SPI1->DR = data[i];
I am trying to receive multiple bytes over SPI. The aim is when the master starts the SPI transfer, slave MCU is interrupted, and it should read the data via SPI and store it in an array, which will be then used by my application for other operations such as determining the device ID and the contents of the packet.
void interrupt __high_priority my_isr_high(void) {
if (PIR1bits.SSP1IF) { // Interrupt from SPI?
rx[buffer_pointer] = SSP1BUF; // Get data from MSSP and store in RX buffer
buffer_pointer++; // Next data
if (buffer_pointer < FRAME_SIZE) // Ended?
SSP1BUF = tx[buffer_pointer]; // Send next byte to SPI
else
buffer_pointer = FRAME_SIZE;
PIR1bits.SSP1IF = 0; // Clear interrupt flag
}
}
However, I am not receiving the 3 bytes correctly. I am sending the following from the master:
dataPacket[0] = 0x43; // Decimal 67
dataPacket[1] = 0x42; //66
dataPacket[2] = 0x41; //65
While I am receiving as follows from the ISR():
rx[0]: 67
rx[1]: 65
rx[2]: 67
Am I missing something or handling the SPI incorrectly?
This will really solve the issue that I am stuck with and maybe will also help others who what to rx multiple bytes.
I am sharing my codes here so that it helps to find the solution quickly. Also included is a .zip file for compiling. Check the Codes here
So far the above code did not work for me properly. Therefore, after a little bit of digging online and other forums I found the following way to read multiple bytes:
uint8_t SPI_ExchangeHandler(uint8_t byte){
static uint8_t i = 0;
for(i=0; i<3; i++){
SSP1BUF =0x00;
while(!SSP1STATbits.BF);
rx_buff[i]=SSP1BUF;
}
State = SEND;
return byte;
}
Although the above codes give me what expected (i.e, correct data packets in the ordered manner), however, it misses two SPI interrupts every time and then displays/captures the correct data. Hence, two sets of data are always lost and then the third one is received correctly.
Is something wrongly configured or missing?
Finally, I managed to receive all the 3 bytes correctly. Sharing the codes below:
My interrupt service routine that triggers the MCU when master SPI has data to send.
void interrupt INTERRUPT_InterruptManager (void){
if(PIE1bits.SSP1IE == 1 && PIR1bits.SSP1IF == 1)
{
SPI_ISR();
}
}
The SPI_ISR code was autogenerated by the MCC GUI.
void SPI_ISR(void)
{
SSP1BUF = SPI_xchgHandler(SSP1BUF);
}
void SPI_setExchangeHandler(uint8_t (* InterruptHandler)(uint8_t))
{
SPI_xchgHandler = InterruptHandler;
}
Then I handle the SPI via a custom function using SPI_setExchangeHandler() as follows:
#define FRAME_SIZE 10 // Frame fixed size
volatile static uint8_t rx_buff[FRAME_SIZE]; //RX buffer
uint8_t SPI_ExchangeHandler(uint8_t byte)
{
static uint8_t i = 0;
rx_buff[i]=SSP1BUF;
i++;
if(i <= 2){
rx_buff[i]=SSP1BUF;
SSP1BUF = 0x00;
while(!SSP1STATbits.BF){};
i++;
}
else{
i = 2;
}
PIR1bits.SSP1IF = 0; // Clear the SPI interrupt flag
State = SEND;
return byte;
}
And I print out the values as follows for debugging:
printf("CMD:%d \n", rx_buff[0]);
printf("BUF1: %d \n", rx_buff[1]);
printf("BUF2: %d \n\n", rx_buff[2]);
However, I am pretty sure this is not the best/optimized way to handle multiple bytes from SPI, therefore, if there is an alternative, share...
I need to read values form a distance sensor in volts. The sensor sends the voltages binary values to the MUC (Atmega8) and then the atmega8 communicates to my pc using USART with and RS232 cable. The readings displayed on the PC are weird random characters. I don't understand what am I doing wrong.
Here is my code
//USART communicating with Atmega8
#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>
#include <string.h>
//1MHZ Baud 9600
#define F_CPU 1000000
char *Bestbelieve ="t \r\n";
void InitADC()
{
ADMUX=(0<<REFS1)|(1<<REFS1); // For Aref=internal;
ADCSRA=(1<<ADEN)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Prescalar div factor =8
}
uint16_t ReadADC()
{
ADMUX=0x05;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while(!(ADCSRA & (1<<ADIF)));
//Clear ADIF by writing one to it
//Note you may be wondering why we have write one to clear it
//This is standard way of clearing bits in io as said in datasheets.
//The code writes '1' but it result in setting bit to '0' !!!
ADCSRA|=(1<<ADIF);
return(ADC);
}
void Wait()
{
uint8_t i;
for(i=0;i<20;i++)
_delay_loop_2(0);
}
char USARTReadChar()
{
//Wait until a data is available
while(!(UCSRA & (1<<RXC)))
{
//Do nothing
}
//Now USART has got data from host
//and is available is buffer
return UDR;
}
void USARTWriteChar(char* data)
{
//Wait until the transmitter is ready
while(*data)
{ while(!(UCSRA & (1<<UDRE)))
{
//Do nothing
}
//Now write the data to USART buffer
UDR=*data;
data++;
}}
void USARTInit(uint16_t ubrr_value)
{
UBRRL = 12;
UBRRH = 0;
UCSRC=(1<<URSEL)|(3<<UCSZ0);
UCSRB=(1<<RXEN)|(1<<TXEN);
UCSRA=(1<<U2X);
}
int main()
{
uint16_t adc_result;
//Initialize ADC
InitADC();
USARTInit(12); //UBRR = 12
//Loop forever
while(1)
{
adc_result=ReadADC(); // Read Analog value from channel-0
char *result[15];
sprintf(result,"%d",adc_result);
Wait();
USARTWriteChar(adc_result);
/* The code continuously has t outputted and skipped lines.
*/
}
}
You are using sprintf to format your data into result. However, you then use USARTWriteChar on your binary value adc_result.
You need to print out result instead, presumably with a loop over the characters calling USARTWriteChar.
I have an atom board with a Fintek F75111 GPIO. I have info from the manufacturer that the SMbus address to access the chip is 06EH.
I am trying to read and write values to the GPIO in Linux. I have a sample program from manufacturer written for Windows that looks like this.
#include “math.h”
#include “stdio.h”
#include “dos.h”
void main(void){
int SMB_PORT_AD = 0x400;
int SMB_DEVICE_ADD = 0x6E;
/*75111R’s Add=6eh */
//programming DIO as output //0:input 1:Output
/* Index 10, GPIO1x Output pin control */
SMB_Byte_WRITE(SMB_PORT_AD,SMB_DEVICE_ADD,0x10,0xff); delay(10);
//programming DIO default LOW
/* Index 11, GPIO1x Output Data value */
SMB_Byte_WRITE(SMB_PORT_AD,SMB_DEVICE_ADD,0x11,0x00); delay(10);
}
unsigned char SMB_Byte_READ (int SMPORT, int DeviceID, int REG_INDEX)
{
unsigned char SMB_R;
outportb(SMPORT+02, 0x00); /* clear */
outportb(SMPORT+00, 0xff); /* clear */
delay(10);
outportb(SMPORT+04, DeviceID+1); /* clear */
outportb(SMPORT+03, REG_INDEX); /* clear */
outportb(SMPORT+02, 0x48); /* read_byte */
delay(10);
SMB_R= inportb(SMPORT+05);
return SMB_R;
}
void SMB_Byte_WRITE(int SMPORT, int DeviceID, int REG_INDEX, int REG_DATA)
{
outportb(SMPORT+02, 0x00); /* clear */
outportb(SMPORT+00, 0xff); /* clear */
delay(10);
outportb(SMPORT+04, DeviceID); /* clear */
outportb(SMPORT+03, REG_INDEX); /* clear */
outportb(SMPORT+05, REG_DATA); /* read_byte */
outportb(SMPORT+02, 0x48); /* read_byte */
delay(10);
}
I have tried to translate this to Linux compatible functions inb() and outb() and this is what I got.
#include <stdio.h>
#include <sys/io.h>
unsigned int gpio_read(int PORT, int DEVICE, int REG_INDEX){
unsigned int RESPONSE;
outb(0x00, PORT+02);
outb(0xff, PORT+00);
usleep(100);
outb(DEVICE+1, PORT+04);
outb(REG_INDEX, PORT+03);
outb(0x48, PORT+02);
usleep(100);
RESPONSE = inb(PORT+05);
return RESPONSE;
}
unsigned int gpio_write(int PORT, int DEVICE, int REG_INDEX, int REG_DATA){
outb(0x00, PORT+02);
outb(0xff, PORT+00);
usleep(100);
outb(DEVICE, PORT+04);
outb(REG_INDEX, PORT+03);
outb(DATA, PORT+05);
outb(0x48, PORT+02);
usleep(100);
}
void main() {
int PORT = 0x400;
int DEVICE = 0x6E;
unsigned int RESPONSE;
// Ask access to port from kernel
ioperm(0x400, 100, 1);
// GPIO1x set to input (0xff is output)
gpio_write(PORT, DEVICE, 0x10, 0x00);
RESPONSE = gpio_read(PORT, DEVICE, 1);
printf("\n %u \n", RESPONSE);
}
GPIO1X index 0x10 is used to set if the 8 GPIO ports that are connected to GPIO1x are output ports or input ports.
Output values for GPIOs are set using the index 0x11, and if the ports work as input ports then index 0x12 is used for reading input values.
The problem is that I do not know if this is correct or how to read the values (why the read function outputs something before reading?!?)
When I run:
RESPONSE = gpio_read(PORT, DEVICE, X);
Changing X with values from 1..9 I get this as output: 0 8 8 0 0 0 0 0 0
The number 8 confuses me...
Instead of writing directly to the SMBus port, I'd rather use the i2c libraries. I2C (and SMBUS) use two Port Pins, one for the clock and one for the data. The data is trasmitted and received at the clock edges (synchronous), Reading the code, I cannot see clearly which of them (clock or data) is being accessed and when.
To get started I'd use i2ctools as a start point (check this site: http://elinux.org/Interfacing_with_I2C_Devices). This tool helps you to find devices connected to the I2C bus to your microprocessor and also perform basic commmunication.
Hope it helps...
I have a problem , please help me.
for about a project homework ı need read from virtual serial port with microC and send this info to AT89C52 microconttoller..
This is my source code:
int uart_rd;
void main() {
P1=0X00;
UART1_Init(9600);
delay_ms(100);
while(1)
{
if(UART1_Data_Ready()){
uart_rd=UART1_read();
if(uart_rd=='1')
{P1=0X01; delay_ms(1500); P1=0X00; }
if(uart_rd=='2')
{P1=0X02; delay_ms(1500); P1=0X00; }
}
}
}
BUT I cant get info from the port. Where is the mistake.Please help me...
You are defining your UART receive variable (uart_rd) as an int, which is a 2 byte variable. I would expect UART1_read() to return a single byte (char).
I am not familiar with your particular setup or debugging/troubleshooting options, but you might try writing some code to assist in debugging your issue. The following example may be useful. It does assume that LEDs are connected to both port 1 and port 2, so some adjustment may be necessary.
char uart_rd;
void main()
{
UART1_Init(9600); // Initialize UART at 9600 bps
delay_ms(100); // Wait for UART to stabilize
while(1)
{
if(UART1_Data_Ready())
{
P2 = 0xFF; // Turn ON PORT2 LEDs upon data ready
uart_rd = UART1_read(); // Receive data
P1 = uart_rd; // Display data on port 1 LEDs
UART1_write(uart_rd); // Transmit same data back
delay_ms(1500); // Brief delay
P1 = 0x00; // Turn OFF port 1 LEDs
P2 = 0x00; // Turn OFF port 2 LEDs
}
}
}