I have a dsPIC33 with an explorer board 16. The entire code base is fairly lengthy but the problem is isolated to the DMA interrupt. It is not being triggered even though I have pretty much copied the Microchip UARTloopback example. I have read the Microchip manual section for both the UART and DMA thoroughly and the loopback example does work, however when it is implemented with my code it does not. I have checked my entire project to make sure that the DMA channels are not being overwritten or used anywhere else in the project. The same applies to the UART section. I will be including the entire file c file and h file. Functions to focus on are the uart_commInit, BEACON_uart_commPuts, and _DMA3Interrupt. The BEACON_uart_commPuts works and prints to the terminal. Everything compiles
uart.c
/**
* This source file contains functions for using the UARTs.
*
* #todo Write uart_monitor() or ISR to check for UART parity, framing error and DMA collisions
*
* #ingroup CSuart
* #defgroup CSuart UART
* #{
* High level functions for UART with DMA. Function names
* beginning with uart_comm... are for communicating with the transceiver. The
* UART peripheral used for the transceiver can be changed by editing the macros
* in CSuart.h.
*/
/* System & Local Includes */
#include <p33Fxxxx.h>
#include <string.h>
#include "CSdefine.h"
#include "types.h"
#include "CSuart.h"
/* Type and Constant Definitions*/
// Handshake control signals for Devboard USB
#define HS0 BIT4 // RC4
#define HS1 BIT3 // RC3
#define HS2 BIT2 // RC2
#define HS3 BIT5 // RD5
#define HS4 BIT2 // RD2
#define HS5 BIT1 // RD1
// Motherboard control signals
#define CS_SD_BAR BIT5 // RE5
#define OE_USB_BAR BIT1 // RC1
#define OE_MHX_BAR BIT2 // RE2
#define ON_SD_BAR BIT4 // RE4
#define ON_MHX_BAR BIT3 // RE3
/* Global & Local Variables */
// DMA TX and RX buffers for comm UART
static uint16 txBuff[RADIO_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 rxBuff[RADIO_RX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 tx0Buff[BEACON_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 rx0Buff[BEACON_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read from DMA rxBuff
static uint16 *lastRead0 = (uint16 *) &rx0Buff; // Points to next transfer to be read from DMA rxBuff
/* Functions */
/******************************************************************************
**** ****
** **
csk_usb_open() Enable USB on the Dev/Flight hardware
** **
**** ****
******************************************************************************/
void csk_usb_open(void) {
// Disable all control signals to avoid spurious
// writes when -OE_USB goes active (LOW).
PORTD |= (HS5+HS4+HS3 );
TRISD &= ~(HS5+HS4+HS3 );
//
// // Configure -OE_USB as an output, and make
// // it active (i.e., LOW)
PORTC &= ~OE_USB_BAR;
TRISC &= ~OE_USB_BAR;
} /* csk_usb_open() */
/******************************************************************************
**** ****
** **
csk_usb_close() // Disable USB on the Dev/flight hardware
** **
**** ****
******************************************************************************/
void csk_usb_close(void) {
// Restore -OE_USB to an input.
PORTC |= OE_USB_BAR;
TRISC |= OE_USB_BAR;
} /* csk_usb_close() */
/**
* Initializes the UART port with DMA for use for satellite comm (ie. the transceiver).
* This should be called sometime during startup.
*/
void uart_commInit(){
// Configure UART for 9600 8N1 with interrupts to the DMA module
RADIO_UMODEbits.UEN = 0b10; //UxTX, UxRX, UxCTS and UxRTS pins are enabled and used
RADIO_UMODEbits.PDSEL = 0b00; //8-bit data, no parity
RADIO_UBRG = ((Fcyc/38400)/16)-1; //9600 baud //38400 //((Fcyc/38400)/16)-1
//COMM_UBRG = 259; // 9600 baud # 80MHz
RADIO_USTAbits.UTXISEL0 = 0; // Interrupt when there is room in TX FIFO
RADIO_USTAbits.URXISEL = 0; // Interrupt when a character is received
// Configure DMA channel 1 as Comm Uart transmit
DMA1CONbits.DIR = 1; // DMA reads from SRAM, writes to peripheral
DMA1CONbits.AMODE = 00; // Addr. mode is register indirect w/ post increment
DMA1CONbits.MODE = 0b01;// One-shot, no ping-pong mode.
DMA1CONbits.SIZE = 1; // Transfer 1 byte at a time
DMA1REQbits.IRQSEL = 0b0001100; // DMA1 writes to UART1 TX (the Comm uart port.)
DMA1PAD = (volatile unsigned int) &RADIO_UTXREG; //Tell DMA module address of COMM TX register
DMA1STA = __builtin_dmaoffset(txBuff); // Tell DMA module start address of our dma tx buffer
IFS0bits.DMA1IF = 0; // Clear DMA interrupt flag
//IEC0bits.DMA1IE = 1; // Enable DMA interrupt
//Configure DMA channel 0 as Comm Uart receive
DMA0CONbits.MODE = 0b00; // Continuous no Ping-Pong mode
DMA0CNT = RADIO_RX_BUFFER_SIZE - 1;
DMA0REQbits.IRQSEL = 0b0001011; // DMA0 reads from UART1 RX (the Comm uart port.)
DMA0PAD = (volatile unsigned int) &RADIO_URXREG;
DMA0STA = __builtin_dmaoffset(rxBuff); // Tell DMA start addr. of buffer A
//DMA0STB = __builtin_dmaoffset(rxBuffB); // Tell DMA start addr. of buffer B
IFS0bits.DMA0IF = 0; // Clear DMA interrupt flag
//IEC0bits.DMA0IE = 1; // Enable DMA interrupt
DMA0CONbits.CHEN = 1; // Enable RX DMA channel only. TX channel is one-shot mode.
// UART config for CLI
BEACON_UMODEbits.STSEL = 0; //1-stop bit
BEACON_UMODEbits.PDSEL = 0; //No Parity, 8-data bits
BEACON_UMODEbits.ABAUD = 0; // Autobaud Disabled
BEACON_UBRG = ((Fcyc/9600)/16)-1; // 9600 baud # 80Mhz
BEACON_USTAbits.UTXISEL0 = 0; // interrupt after 1 Tx char is transmited
//BEACON_USTAbits.UTXISEL1 = 0;
BEACON_USTAbits.URXISEL = 0; // interrrupt after 1 Rx char is received
BEACON_UMODEbits.UARTEN = 1; // Enable UART
BEACON_USTAbits.UTXEN = 1; // Enable Uart Tx
IEC4bits.U2EIE = 0; // Enable error interrupt
//Tx config for CLI
DMA4REQ = 0x001F; // Uart2 transmiter
DMA4PAD = (volatile unsigned int) &BEACON_UTXREG;// Tell DMA module address of COMM TX register
DMA4CONbits.AMODE = 0; // Addr. mode is register indirect x/ post increment
DMA4CONbits.MODE = 1; // One-Shot
DMA4CONbits.DIR = 1; // reads from RAM writes to peripheral
DMA4CONbits.SIZE = 1;// Transfers 1 byte at a time
// count needs to be pushed into interrupt and counted there, will avoid weird shit
DMA4CNT = 7; // 11 DMA requests
DMA4STA = __builtin_dmaoffset(tx0Buff); // Tell DMA module start address of our dma tx buffer
IFS2bits.DMA4IF = 0; // Clear DMA interrupt flag
IEC2bits.DMA4IE = 1; // Enable DMA interrupt
// Rx config for CLI
DMA3REQ = 0x001E; // Uart2 Receive
DMA3PAD = (volatile unsigned int) &BEACON_URXREG; // Tell DMA module address of COMM RX register
DMA3CONbits.AMODE = 0; // Addr. mode is register indirect x/ post increment
DMA3CONbits.MODE = 2; // Ping-Pong
DMA3CONbits.DIR = 0; // reads from peripheral writes to RAM
DMA3CONbits.SIZE = 0; // Transfers 1 word at a time
DMA3CNT = 7; // 11 DMA requests
DMA3STA = __builtin_dmaoffset(tx0Buff); // Tell DMA start addr. of receive buffer
DMA3STB = __builtin_dmaoffset(rx0Buff); // Tell DMA start addr. of receive buffer
DMA3CONbits.CHEN = 1; // Enable RX DMA channel only. TX channel is one-shot mode.
IFS2bits.DMA3IF = 0; // Clear DMA interrupt
IEC2bits.DMA3IE = 1; // Enable DMA interrupt
// END of added code
// these bits must be at end of file
RADIO_UMODEbits.UARTEN = 1; //enable uart
RADIO_USTAbits.UTXEN = 1; //transmit enabled
}
/**
* Writes a string to the comm Port. The length must be less than COMM_TX_BUFFER_SIZE
* or this function will have no effect.
* #param str The string to write.
* #param len The number of bytes to write
* #pre uart_commInit() must be called before calling this function.
* #note This function call is blocking. It waits until the last transfer is
* finished to begin current transmission. Once current transmission has been
* started then it will return because the DMA module handles transmission of data.
*/
void BEACON_uart_commPuts(char *str, uint16 len){
#if DEBUG_OUTPUT
uint16 *targetAddr;
if(len == 0 || len > BEACON_TX_BUFFER_SIZE)
return; //TODO Handle error
while(!BEACON_commIsTXReady()); // Blocking!
targetAddr = (uint16 *) (DMA4STA + ((unsigned int) &_DMA_BASE)); // Address of DMA buffer
memcpy((void *) targetAddr, (const void *) str, len); // Copy data into DMA buffer
DMA4CNT = len-1; // Send len # of characters
DMA4CONbits.CHEN = 1; // Turn on the DMA channel
DMA4REQbits.FORCE = 1; // Start DMA transfer to comm UART
#endif
}
/**
* Retrieves a string from the Comm. Port. The caller must ensure that the 'str'
* parameter can handle the number of bytes being requested in parameter 'len'.
* #param str The string to store the received characters in.
* #param len The maximum number of characters to return. The number of chars
* copied to str will be less than or equal to len.
* #return int16 The number of bytes copied to str if non-negative or an error
* code if negative.
* #pre uart_commInit() must be called before calling this function.
* #todo Add overrun detection
* #todo Implement error codes if necessary.
*/
int16 RADIO_uart_commGets(char *str, uint16 len){
/* The DMA transfers 2 bytes of data into the DMA buffer for every byte it
* receives from the UART (see dsPIC33 reference manual DMA chapter). The
* lower byte is the data received by the UART and the upper byte has 2
* status bits. There is one DMA receive buffer (no Ping-Pong mode) which the
* DMA starts to fill 2 bytes at a time until the buffer is full then goes
* back to the beginning and starts to put new characters in the beginning
* of the buffer again. This code reads up to 'len' bytes (not transfers!) from the buffer
* starting from the last location readmup to the last byte available in
* the DMA buffer. If the DMA rolled over to the beginning since the last read,
* this function reads until the end of the buffer, then from the beginning.
* This should be called often enough to prevent overruns.
*
* NOTE: For every 2 bytes this function reads from the DMA buffer it only
* returns one because the upper byte of each transfer are status bits.
*/
uint16 numTransfers, i; // # of DMA transfers (not bytes!) to return to caller.
uint16 *lastArrived = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
//static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read
if(lastArrived < lastRead){ // Rollover occured
// (1) # of transfers till end of buffer.
// (2) # of transfers in the beginning of buffer.
numTransfers = (uint16) ((rxBuff + RADIO_RX_BUFFER_SIZE - 1) - lastRead);
numTransfers += (uint16) (lastArrived - rxBuff);
}else{
numTransfers = (uint16) (lastArrived - lastRead);
}
if(len < numTransfers) // Don't give caller more bytes than they can handle
numTransfers = len;
for(i = 0; i < numTransfers; i++){ // Now copy chars into caller's buffer
/*if(i == 0){
uart_commGetc();
continue;
}*/
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rxBuff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to callers buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return i; // # of bytes returned in parameter 1.
}
int16 BEACON_uart_commGets(char *str, uint16 len){
/* The DMA transfers 2 bytes of data into the DMA buffer for every byte it
* receives from the UART (see dsPIC33 reference manual DMA chapter). The
* lower byte is the data received by the UART and the upper byte has 2
* status bits. There is one DMA receive buffer (no Ping-Pong mode) which the
* DMA starts to fill 2 bytes at a time until the buffer is full then goes
* back to the beginning and starts to put new characters in the beginning
* of the buffer again. This code reads up to 'len' bytes (not transfers!) from the buffer
* starting from the last location readmup to the last byte available in
* the DMA buffer. If the DMA rolled over to the beginning since the last read,
* this function reads until the end of the buffer, then from the beginning.
* This should be called often enough to prevent overruns.
*
* NOTE: For every 2 bytes this function reads from the DMA buffer it only
* returns one because the upper byte of each transfer are status bits.
*/
uint16 numTransfers, i; // # of DMA transfers (not bytes!) to return to caller.
uint16 *lastArrived = (uint16 *)(DMA3STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
//static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read
if(lastArrived < lastRead){ // Rollover occured
// (1) # of transfers till end of buffer.
// (2) # of transfers in the beginning of buffer.
numTransfers = (uint16) ((rx0Buff + BEACON_RX_BUFFER_SIZE - 1) - lastRead);
numTransfers += (uint16) (lastArrived - rx0Buff);
}else{
numTransfers = (uint16) (lastArrived - lastRead);
}
if(len < numTransfers) // Don't give caller more bytes than they can handle
numTransfers = len;
for(i = 0; i < numTransfers; i++){ // Now copy chars into caller's buffer
/*if(i == 0){
uart_commGetc();
continue;
}*/
if(lastRead >= rx0Buff + BEACON_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rx0Buff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to callers buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return i; // # of bytes returned in parameter 1.
}
/**
* Retrieves a single character from the comm receive buffer.
* #return (int16) returns a signed integer. If the value is less than zero there
* were no characters in the UART receive buffer to return. Otherwise, the return
* value should be cast to a char and used accordingly.
* #pre uart_commInit() must be called before calling this function.
*/
int16 RADIO_uart_commGetc(){
int16 retValue;
if(RADIO_uart_commNumRXBytes() > 0){
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rxBuff; // Start reading from beginning now
}
retValue = (int16) *lastRead;
lastRead++;
return retValue;
}
return -1;
}
/**
* Retrieves a single character from the comm receive buffer.
* #return (int16) returns a signed integer. If the value is less than zero there
* were no characters in the UART receive buffer to return. Otherwise, the return
* value should be cast to a char and used accordingly.
* #pre uart_commInit() must be called before calling this function.
*/
int16 BEACON_uart_commGetc(){
int16 retValue;
if(BEACON_uart_commNumRXBytes() > 0){
if(lastRead >= rx0Buff + BEACON_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rx0Buff; // Start reading from beginning now
}
retValue = (int16) *lastRead;
lastRead++;
return retValue;
}
return -1;
}
/**
* Looks for and retrieves a string from the comm port up to and including the
* specified terminating character. If the terminating character does not exist
* in the uart buffer no characters are copied to str and -1 is returned.
* #param str A buffer to stored the received data in
* #param len Maximum number of characters to retrieve
* #param terminator the terminating character
* #return The number of characters copied to str, -1 if no terminator not found or buffer to small for command
*/
int16 uart_commGetToChar(char *str, uint16 len, char terminator){
BOOL foundChar = FALSE;
int16 i, strLen = 0; // strLen is the value we will return
uint16 *tempPtr = lastRead; // Points after the last read DMA transfer (transfer = 2 bytes)
uint16 *lastArrived = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
len = (len < (i = RADIO_uart_commNumRXBytes())) ? len : i; // If numCharsReceived > len then len = numCharsReceived
// Look for null terminating character
while(!foundChar){ // Loop until char is found or 'till end of received chars
if(strLen >= len){
return -1; // Provided buffer not long enough or terminating char not found.
}
if((char) (*tempPtr & 0xFF) == terminator){ // Found terminating char?
foundChar = TRUE;
strLen++; // To count terminating character
}else{
strLen++; // Increment # of transfers we're planning to copy to user's buffer
tempPtr++; // Increment pointer to the receive buffer
if(tempPtr >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover in rxBuff
tempPtr = rxBuff; // Start reading from beginning now
}
}
}
for(i = 0; i < strLen; i++){ // Now copy chars into caller's buffer
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover in rxBuff
lastRead = rxBuff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to caller's buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return strLen; // # of bytes INCLUDING terminating character
}
/**
* Returns the number of unread characters in the comm UART buffer.
* #return (int16) number of unread chars in comm UART buffer
* #pre uart_commInit() must be called before calling this function.
*/
int16 RADIO_uart_commNumRXBytes(){
int16 retValue;
uint16 *lastReceivedChar = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE));
if(lastReceivedChar >= lastRead){
return (int16) (lastReceivedChar - lastRead);
}else{
retValue = (int16) ((uint16 *)(&rxBuff + RADIO_TX_BUFFER_SIZE) - lastRead);
retValue += (uint16) (lastReceivedChar - (uint16 *)&rxBuff);
return retValue;
}
}
int16 BEACON_uart_commNumRXBytes(){
int16 retValue;
uint16 *lastReceivedChar = (uint16 *)(DMA2STA + ((unsigned int) &_DMA_BASE));
if(lastReceivedChar >= lastRead){
return (int16) (lastReceivedChar - lastRead);
}else{
retValue = (int16) ((uint16 *)(&rx0Buff + BEACON_TX_BUFFER_SIZE) - lastRead);
retValue += (uint16) (lastReceivedChar - (uint16 *)&rx0Buff);
return retValue;
}
}
/* Interrupt Handlers */
//void __attribute__((__interrupt__,no_auto_psv)) _U2EInterrupt(void){
// TODO Handle Uart Error
//}
/**
* Comm receive DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA0Interrupt(void){
IFS0bits.DMA0IF = 0; // Clear DMA interrupt flag
}
/**
* Comm transmit DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA1Interrupt(void){
IFS0bits.DMA1IF = 0; // Clear DMA interrupt flag
}
/**
* Comm receive DMA interrupt service routine.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA3Interrupt(void){
static unsigned int BufferCount = 0;
if(BufferCount == 0){
DMA4STA = __builtin_dmaoffset(tx0Buff);
}
else{
DMA4STA = __builtin_dmaoffset(rx0Buff);
}
DMA4CONbits.CHEN = 1; // Re-enable DMA3 channel
DMA4REQbits.FORCE = 1; // manual start the transfers, if we doing predetermined transfer size
BufferCount ^= 1;
IFS2bits.DMA3IF = 0; // Clear DMA3 Interrupt flag
}
/**
* Comm transmit DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA4Interrupt(void){
IFS2bits.DMA4IF = 0; // Clear DMA interrupt flag
}
/**
* #}
*/
uart.h
/**
* This header file provides function prototypes and macros for UART ports.
*
* #ingroup CSuart
*/
/**
* #ingroup CSuart
* #{
*/
#ifndef CSUART_H
#define CSUART_H
/* Include Files */
#include <p33Fxxxx.h>
/**
* Register definitions for Comm port uart
* Change these values to use the other uart port.
* WARNING: Must also change values in uart_commInit(). (DMA1REQbits.IRQSEL)
* #cond
*/
/*NOTE:(8/20/14, 3:53pm) these macros have been changed, U2 -> U1 */
#define RADIO_UMODE U1MODE
#define RADIO_UMODEbits U1MODEbits
#define RADIO_USTA U1STA
#define RADIO_USTAbits U1STAbits
#define RADIO_URXREG U1RXREG
#define RADIO_UTXREG U1TXREG
#define RADIO_UBRG U1BRG
#define RADIO_URXIF IFS0bits.U1RXIF // Comm uart receive interrupt flag
#define RADIO_UTXIF IFS0bits.U1TXIF // Comm uart transmite interrupt flag
#define RADIO_RXIntEnable() {IEC0bits.U1RXIE = 1;}
#define RADIO_TXIntEnable() {IEC0bits.U1TXIE = 1;}
#define RADIO_ErrorIntEnable() {IEC4bits.U1EIE = 1;}
#define RADIO_RXIntDisable() {IEC0bits.U1RXIE = 0;}
#define RADIO_TXIntDisable() {IEC0bits.U1TXIE = 0;}
#define RADIO_ErrorIntDisable() {IEC4bits.U1EIE = 0;}
#define BEACON_UMODEbits U2MODEbits
#define BEACON_USTAbits U2STAbits
#define BEACON_URXREG U2RXREG
#define BEACON_UTXREG U2TXREG
#define BEACON_UBRG U2BRG
#define BEACON_IFSbits IFS2bits
#define RADIO_TX_BUFFER_SIZE 283 /// Size of comm port's DMA transmit buffer in bytes
#define RADIO_RX_BUFFER_SIZE 128 /// Size of comm port's DMA receive buffer in bytes
#define BEACON_TX_BUFFER_SIZE 128 /// Size of comm port's DMA transmit buffer in bytes
#define BEACON_RX_BUFFER_SIZE 128 /// Size of comm port's DMA receive buffer in bytes
/**
* Returns 1 when the comm port UART is ready to transmit, and 0 otherwise.
*/
#define RADIO_commIsTXReady() (RADIO_USTAbits.TRMT)
#define BEACON_commIsTXReady() (BEACON_USTAbits.TRMT)
/* Function Prototypes */
void uart_commInit();
void BEACON_uart_commPuts(char *str, uint16 len);
void uart0_commPuts(char *str, uint16 len);
int16 RADIO_uart_commGets(char *str, uint16 len);
//int16 uart0_commGets(char *str, uint16 len);
int16 RADIO_uart_commGetc();
//int16 uart0_commGetc();
int16 uart_commGetToChar(char *str, uint16 len, char terminator);
//int16 uart0_commGetToChar(char *str, uint16 len, char terminator);
int16 RADIO_uart_commNumRXBytes();
//int16 uart0_commNumRXBytes();
/**
* #}
*/
#endif /* CSUART_H */
Related
I'm trying to implement polling functionality into my simple Linux kernel module called gpio_driver for my Raspberry Pi which should notify the user space poll function about the change of state of one of the GPIO pins (button push).
What I did in my gpio_driver is set the internal pull down on my GPIO_04 pin and direction to input, so when I press the button connected to the pin on one side and +5V on the other, it should generate a pulse which should notify the user space poll function that the button push happened and end the user space program.
The user space program code:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <poll.h>
int main(int argc, char *argv[])
{
char str[256];
struct pollfd pfd;
int fd, gpio;
char buf[8];
sprintf(str, "/dev/gpio_driver");
if ((fd = open(str, O_RDONLY)) < 0)
{
fprintf(stderr, "Failed, gpio %d not exported.\n", gpio);
exit(1);
}
pfd.fd = fd;
pfd.events = POLLPRI;
lseek(fd, 0, SEEK_SET); /* consume any prior interrupt */
read(fd, buf, sizeof buf);
poll(&pfd, 1, -1); /* wait for interrupt */
lseek(fd, 0, SEEK_SET); /* consume interrupt */
read(fd, buf, sizeof buf);
exit(0);
}
Complete driver code (poll function implementation at the end of file):
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <linux/ioctl.h>
#include <linux/poll.h>
MODULE_LICENSE("Dual BSD/GPL");
/* if defined, timer callback will implement LED0 flashing and
SW0 reading after each interval */
#define TEST
// timer interval defined as (TIMER_SEC + TIMER_NANO_SEC)
#define TIMER_SEC 0
#define TIMER_NANO_SEC 250*1000*1000 /* 250ms */
// NOTE: Check Broadcom BCM8325 datasheet, page 91+
// NOTE: GPIO Base address is set to 0x7E200000,
// but it is VC CPU BUS address, while the
// ARM physical address is 0x3F200000, what
// can be seen in pages 5-7 of Broadcom
// BCM8325 datasheet, having in mind that
// total system ram is 0x3F000000 (1GB - 16MB)
// instead of 0x20000000 (512 MB)
/* GPIO registers base address. */
#define BCM2708_PERI_BASE (0x3F000000)
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
#define GPIO_ADDR_SPACE_LEN (0xB4)
//--
//Handle GPIO: 0-9
/* GPIO Function Select 0. */
#define GPFSEL0_OFFSET (0x00000000)
//Handle GPIO: 10-19
/* GPIO Function Select 1. */
#define GPFSEL1_OFFSET (0x00000004)
//Handle GPIO: 20-29
/* GPIO Function Select 2. */
#define GPFSEL2_OFFSET (0x00000008)
//Handle GPIO: 30-39
/* GPIO Function Select 3. */
#define GPFSEL3_OFFSET (0x0000000C)
//Handle GPIO: 40-49
/* GPIO Function Select 4. */
#define GPFSEL4_OFFSET (0x00000010)
//Handle GPIO: 50-53
/* GPIO Function Select 5. */
#define GPFSEL5_OFFSET (0x00000014)
//--
//GPIO: 0-31
/* GPIO Pin Output Set 0. */
#define GPSET0_OFFSET (0x0000001C)
//GPIO: 32-53
/* GPIO Pin Output Set 1. */
#define GPSET1_OFFSET (0x00000020)
//--
//GPIO: 0-31
/* GPIO Pin Output Clear 0. */
#define GPCLR0_OFFSET (0x00000028)
//GPIO: 32-53
/* GPIO Pin Output Clear 1. */
#define GPCLR1_OFFSET (0x0000002C)
//--
//GPIO: 0-31
/* GPIO Pin Level 0. */
#define GPLEV0_OFFSET (0x00000034)
//GPIO: 32-53
/* GPIO Pin Level 1. */
#define GPLEV1_OFFSET (0x00000038)
//--
//GPIO: 0-53
/* GPIO Pin Pull-up/down Enable. */
#define GPPUD_OFFSET (0x00000094)
//GPIO: 0-31
/* GPIO Pull-up/down Clock Register 0. */
#define GPPUDCLK0_OFFSET (0x00000098)
//GPIO: 32-53
/* GPIO Pull-up/down Clock Register 1. */
#define GPPUDCLK1_OFFSET (0x0000009C)
//--
/* PUD - GPIO Pin Pull-up/down */
typedef enum {PULL_NONE = 0, PULL_DOWN = 1, PULL_UP = 2} PUD;
//--
//000 = GPIO Pin 'x' is an input
//001 = GPIO Pin 'x' is an output
// By default GPIO pin is being used as an input
typedef enum {GPIO_DIRECTION_IN = 0, GPIO_DIRECTION_OUT = 1} DIRECTION;
//--
/* GPIO pins available on connector p1. */
#define GPIO_02 (2)
#define GPIO_03 (3)
#define GPIO_04 (4)
#define GPIO_05 (5)
#define GPIO_06 (6)
#define GPIO_07 (7)
#define GPIO_08 (8)
#define GPIO_09 (9)
#define GPIO_10 (10)
#define GPIO_11 (11)
#define GPIO_12 (12)
#define GPIO_13 (13)
#define GPIO_14 (14)
#define GPIO_15 (15)
#define GPIO_16 (16)
#define GPIO_17 (17)
#define GPIO_18 (18)
#define GPIO_19 (19)
#define GPIO_20 (20)
#define GPIO_21 (21)
#define GPIO_22 (22)
#define GPIO_23 (23)
#define GPIO_24 (24)
#define GPIO_25 (25)
#define GPIO_26 (26)
#define GPIO_27 (27)
/* Declaration of gpio_driver.c functions */
int gpio_driver_init(void);
void gpio_driver_exit(void);
static int gpio_driver_open(struct inode *, struct file *);
static int gpio_driver_release(struct inode *, struct file *);
static ssize_t gpio_driver_read(struct file *, char *buf, size_t , loff_t *);
static ssize_t gpio_driver_write(struct file *, const char *buf, size_t , loff_t *);
static unsigned int gpio_driver_poll(struct file *, poll_table *);
/* Structure that declares the usual file access functions. */
struct file_operations gpio_driver_fops =
{
open : gpio_driver_open,
release : gpio_driver_release,
read : gpio_driver_read,
write : gpio_driver_write,
poll : gpio_driver_poll
};
static DECLARE_WAIT_QUEUE_HEAD(gpio_driver_wait);
/* Declaration of the init and exit functions. */
module_init(gpio_driver_init);
module_exit(gpio_driver_exit);
/* Major number. */
int gpio_driver_major;
/* Buffer to store data. */
#define BUF_LEN 80
char* gpio_driver_buffer;
/* Virtual address where the physical GPIO address is mapped */
void* virt_gpio_base;
/*
* GetGPFSELReg function
* Parameters:
* pin - number of GPIO pin;
*
* return - GPFSELn offset from GPIO base address, for containing desired pin control
* Operation:
* Based on the passed GPIO pin number, finds the corresponding GPFSELn reg and
* returns its offset from GPIO base address.
*/
unsigned int GetGPFSELReg(char pin)
{
unsigned int addr;
if(pin >= 0 && pin <10)
addr = GPFSEL0_OFFSET;
else if(pin >= 10 && pin <20)
addr = GPFSEL1_OFFSET;
else if(pin >= 20 && pin <30)
addr = GPFSEL2_OFFSET;
else if(pin >= 30 && pin <40)
addr = GPFSEL3_OFFSET;
else if(pin >= 40 && pin <50)
addr = GPFSEL4_OFFSET;
else /*if(pin >= 50 && pin <53) */
addr = GPFSEL5_OFFSET;
return addr;
}
/*
* GetGPIOPinOffset function
* Parameters:
* pin - number of GPIO pin;
*
* return - offset of the pin control bit, position in control registers
* Operation:
* Based on the passed GPIO pin number, finds the position of its control bit
* in corresponding control registers.
*/
char GetGPIOPinOffset(char pin)
{
if(pin >= 0 && pin <10)
pin = pin;
else if(pin >= 10 && pin <20)
pin -= 10;
else if(pin >= 20 && pin <30)
pin -= 20;
else if(pin >= 30 && pin <40)
pin -= 30;
else if(pin >= 40 && pin <50)
pin -= 40;
else /*if(pin >= 50 && pin <53) */
pin -= 50;
return pin;
}
/*
* SetInternalPullUpDown function
* Parameters:
* pin - number of GPIO pin;
* pull - set internal pull up/down/none if PULL_UP/PULL_DOWN/PULL_NONE selected
* Operation:
* Sets to use internal pull-up or pull-down resistor, or not to use it if pull-none
* selected for desired GPIO pin.
*/
void SetInternalPullUpDown(char pin, PUD pull)
{
unsigned int gppud_offset;
unsigned int gppudclk_offset;
unsigned int tmp;
unsigned int mask;
/* Get the offset of GPIO Pull-up/down Register (GPPUD) from GPIO base address. */
gppud_offset = GPPUD_OFFSET;
/* Get the offset of GPIO Pull-up/down Clock Register (GPPUDCLK) from GPIO base address. */
gppudclk_offset = (pin < 32) ? GPPUDCLK0_OFFSET : GPPUDCLK1_OFFSET;
/* Get pin offset in register . */
pin = (pin < 32) ? pin : pin - 32;
/* Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither
to remove the current Pull-up/down). */
iowrite32(pull, virt_gpio_base + gppud_offset);
/* Wait 150 cycles – this provides the required set-up time for the control signal */
/* Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to
modify – NOTE only the pads which receive a clock will be modified, all others will
retain their previous state. */
tmp = ioread32(virt_gpio_base + gppudclk_offset);
mask = 0x1 << pin;
tmp |= mask;
iowrite32(tmp, virt_gpio_base + gppudclk_offset);
/* Wait 150 cycles – this provides the required hold time for the control signal */
/* Write to GPPUD to remove the control signal. */
iowrite32(PULL_NONE, virt_gpio_base + gppud_offset);
/* Write to GPPUDCLK0/1 to remove the clock. */
tmp = ioread32(virt_gpio_base + gppudclk_offset);
mask = 0x1 << pin;
tmp &= (~mask);
iowrite32(tmp, virt_gpio_base + gppudclk_offset);
}
/*
* SetGpioPinDirection function
* Parameters:
* pin - number of GPIO pin;
* direction - GPIO_DIRECTION_IN or GPIO_DIRECTION_OUT
* Operation:
* Sets the desired GPIO pin to be used as input or output based on the direcation value.
*/
void SetGpioPinDirection(char pin, DIRECTION direction)
{
unsigned int GPFSELReg_offset;
unsigned int tmp;
unsigned int mask;
/* Get base address of function selection register. */
GPFSELReg_offset = GetGPFSELReg(pin);
/* Calculate gpio pin offset. */
pin = GetGPIOPinOffset(pin);
/* Set gpio pin direction. */
tmp = ioread32(virt_gpio_base + GPFSELReg_offset);
if(direction)
{ //set as output: set 1
mask = 0x1 << (pin*3);
tmp |= mask;
}
else
{ //set as input: set 0
mask = ~(0x1 << (pin*3));
tmp &= mask;
}
iowrite32(tmp, virt_gpio_base + GPFSELReg_offset);
}
/*
* GetGpioPinDirection function
* Parameters:
* pin - number of GPIO pin;
* Operation:
* Gets the desired GPIO pin's direction and returns 0 for IN and 1 for OUT.
*/
int GetGpioPinDirection(char pin)
{
unsigned int GPFSELReg_offset;
unsigned int tmp;
unsigned int mask;
/* Get base address of function selection register. */
GPFSELReg_offset = GetGPFSELReg(pin);
/* Calculate gpio pin offset. */
pin = GetGPIOPinOffset(pin);
/* Get gpio pin direction. */
tmp = ioread32(virt_gpio_base + GPFSELReg_offset);
mask = 0x1 << (pin*3);
tmp &= mask;
tmp=tmp>>(pin*3);
return tmp;
}
/*
* SetGpioPin function
* Parameters:
* pin - number of GPIO pin;
* Operation:
* Sets the desired GPIO pin to HIGH level. The pin should previously be defined as output.
*/
void SetGpioPin(char pin)
{
unsigned int GPSETreg_offset;
unsigned int tmp;
/* Get base address of gpio set register. */
GPSETreg_offset = (pin < 32) ? GPSET0_OFFSET : GPSET1_OFFSET;
pin = (pin < 32) ? pin : pin - 32;
/* Set gpio. */
tmp = 0x1 << pin;
iowrite32(tmp, virt_gpio_base + GPSETreg_offset);
}
/*
* ClearGpioPin function
* Parameters:
* pin - number of GPIO pin;
* Operation:
* Sets the desired GPIO pin to LOW level. The pin should previously be defined as output.
*/
void ClearGpioPin(char pin)
{
unsigned int GPCLRreg_offset;
unsigned int tmp;
/* Get base address of gpio clear register. */
GPCLRreg_offset = (pin < 32) ? GPCLR0_OFFSET : GPCLR1_OFFSET;
pin = (pin < 32) ? pin : pin - 32;
/* Clear gpio. */
tmp = 0x1 << pin;
iowrite32(tmp, virt_gpio_base + GPCLRreg_offset);
}
/*
* GetGpioPinValue function
* Parameters:
* pin - number of GPIO pin;
*
* return - the level read from desired GPIO pin
* Operation:
* Reads the level from the desired GPIO pin and returns the read value.
*/
char GetGpioPinValue(char pin)
{
unsigned int GPLEVreg_offset;
unsigned int tmp;
unsigned int mask;
/* Get base address of gpio level register. */
GPLEVreg_offset = (pin < 32) ? GPLEV0_OFFSET : GPLEV1_OFFSET;
pin = (pin < 32) ? pin : pin - 32;
/* Read gpio pin level. */
tmp = ioread32(virt_gpio_base + GPLEVreg_offset);
mask = 0x1 << pin;
tmp &= mask;
return (tmp >> pin);
}
/*
* Initialization:
* 1. Register device driver
* 2. Allocate buffer
* 3. Initialize buffer
* 4. Map GPIO Physical address space to virtual address
* 5. Initialize GPIO pin
*/
int gpio_driver_init(void)
{
int result = -1;
printk(KERN_INFO "Inserting gpio_driver module\n");
/* Registering device. */
result = register_chrdev(0, "gpio_driver", &gpio_driver_fops);
if (result < 0)
{
printk(KERN_INFO "gpio_driver: cannot obtain major number %d\n", gpio_driver_major);
return result;
}
gpio_driver_major = result;
printk(KERN_INFO "gpio_driver major number is %d\n", gpio_driver_major);
/* Allocating memory for the buffer. */
gpio_driver_buffer = kmalloc(BUF_LEN, GFP_KERNEL);
if (!gpio_driver_buffer)
{
result = -ENOMEM;
goto fail_no_mem;
}
/* Initialize data buffer. */
memset(gpio_driver_buffer, 0, BUF_LEN);
/* map the GPIO register space from PHYSICAL address space to virtual address space */
virt_gpio_base = ioremap(GPIO_BASE, GPIO_ADDR_SPACE_LEN);
if(!virt_gpio_base)
{
result = -ENOMEM;
goto fail_no_virt_mem;
}
/* Initialize GPIO pin. */
SetGpioPinDirection(GPIO_04, GPIO_DIRECTION_IN);
SetInternalPullUpDown(GPIO_04, PULL_DOWN); // rising edge
return 0;
fail_no_virt_mem:
/* Freeing buffer gpio_driver_buffer. */
if (gpio_driver_buffer)
{
kfree(gpio_driver_buffer);
}
fail_no_mem:
/* Freeing the major number. */
unregister_chrdev(gpio_driver_major, "gpio_driver");
return result;
}
/*
* Cleanup:
* 1. stop the timer
* 2. release GPIO pins (clear all outputs, set all as inputs and pull-none to minimize the power consumption)
* 3. Unmap GPIO Physical address space from virtual address
* 4. Free buffer
* 5. Unregister device driver
*/
void gpio_driver_exit(void)
{
printk(KERN_INFO "Removing gpio_driver module..\n");
/* Clear GPIO pins. */
ClearGpioPin(GPIO_04);
/* Set GPIO pins as inputs and disable pull-ups. */
SetGpioPinDirection(GPIO_04, GPIO_DIRECTION_IN);
SetInternalPullUpDown(GPIO_04, PULL_NONE);
/* Unmap GPIO Physical address space. */
if (virt_gpio_base)
{
iounmap(virt_gpio_base);
}
/* Freeing buffer gpio_driver_buffer. */
if (gpio_driver_buffer)
{
kfree(gpio_driver_buffer);
}
/* Freeing the major number. */
unregister_chrdev(gpio_driver_major, "gpio_driver");
}
/* File open function. */
static int gpio_driver_open(struct inode *inode, struct file *filp)
{
/* Success. */
return 0;
}
/* File close function. */
static int gpio_driver_release(struct inode *inode, struct file *filp)
{
/* Success. */
return 0;
}
/* File read function */
static ssize_t gpio_driver_read(struct file *filp, char *buf, size_t len, loff_t *f_pos)
{
/* Size of valid data in gpio_driver - data to send in user space. */
int data_size = 0;
/* Copy GPIO pin state to user space. */
gpio_driver_buffer[0]=GetGpioPinValue(GPIO_04);
/* TODO: fill gpio_driver_buffer here. */
if (*f_pos == 0)
{
/* Get size of valid data. */
data_size = strlen(gpio_driver_buffer);
/* Send data to user space. */
if (copy_to_user(buf, gpio_driver_buffer, data_size) != 0)
{
return -EFAULT;
}
else
{
(*f_pos) += data_size;
return data_size;
}
}
else
{
return 0;
}
}
/* File write function */
static ssize_t gpio_driver_write(struct file *filp, const char *buf, size_t len, loff_t *f_pos)
{
printk(KERN_ALERT "Sorry, this operation isn't supported.\n");
return -EPERM; // Operation not permitted error
}
static unsigned int gpio_driver_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(filp, &gpio_driver_wait, wait);
if(GetGpioPinValue(GPIO_04)!=0)
gpio_driver_buffer[0] = 1;
if(gpio_driver_buffer[0] == 1)
{
mask |= POLLIN | POLLPRI;
wake_up_interruptible(&gpio_driver_wait);
}
gpio_driver_buffer[0] = 0;
return mask;
}
However, when I run my user space program, it doesn't react to my button pushes and it never exits. I'm pretty new to polling all the code written in the driver related to polling and user program I picked up online from different sources and some books (mainly Linux Device Drivers, 3rd edition, chapter 6). What am I doing wrong?
I have been trying to setup a uart on the EFM32 Starter kind and I am now able to send characters out of the EFM32 Starter kit board to a computer, but when I try to receive from the computer using the example, my interrupt gets called once, but the data I get is 0x0 and then after the first character I dont receive the interrupt again.
I modified the code from the application note software that can be found on silab's website: USART/UART Asynchronous mode Application Note software
I have added the code to this question as well. Has anyone else encountered this? I must be doing something silly.
I checked the RXDATA register in the debugger and it keeps showing 0 even when I press a the "a" character on the keyboard. Also the interrupt only fires once, with the rxdata being 0, then I never get an interrupt after that.
Thanks in advance.
/******************************************************************************
* #file main.c
* #brief USART/UART Asynchronous mode Application Note software example
* #author Silicon Labs
* #version 1.03
******************************************************************************
* #section License
* <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
*******************************************************************************
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
* obligation to support this Software. Silicon Labs is providing the
* Software "AS IS", with no express or implied warranties of any kind,
* including, but not limited to, any implied warranties of merchantability
* or fitness for any particular purpose or warranties against infringement
* of any proprietary rights of a third party.
*
* Silicon Labs will not be liable for any consequential, incidental, or
* special damages, or any other relief, or for any claim by any third party,
* arising from your use of this Software.
*
******************************************************************************/
#include <stdint.h>
#include "em_device.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_usart.h"
#include "bsp.h"
/* Function prototypes */
void uartSetup(void);
void cmuSetup(void);
void uartPutData(uint8_t * dataPtr, uint32_t dataLen);
uint32_t uartGetData(uint8_t * dataPtr, uint32_t dataLen);
void uartPutChar(uint8_t charPtr);
uint8_t uartGetChar(void);
/* Declare some strings */
const char welcomeString[] = "EFM32 RS-232 - Please press a key\r\n";
const char overflowString[] = "\n---RX OVERFLOW---\n";
const uint32_t welLen = sizeof(welcomeString) - 1;
const uint32_t ofsLen = sizeof(overflowString) - 1;
/* Define termination character */
#define TERMINATION_CHAR '.'
/* Declare a circular buffer structure to use for Rx and Tx queues */
#define BUFFERSIZE 256
volatile struct circularBuffer
{
uint8_t data[BUFFERSIZE]; /* data buffer */
uint32_t rdI; /* read index */
uint32_t wrI; /* write index */
uint32_t pendingBytes; /* count of how many bytes are not yet handled */
bool overflow; /* buffer overflow indicator */
} rxBuf, txBuf = { {0}, 0, 0, 0, false };
/* Setup UART1 in async mode for RS232*/
static USART_TypeDef * uart = USART1;
static USART_InitAsync_TypeDef uartInit = USART_INITASYNC_DEFAULT;
/******************************************************************************
* #brief Main function
*
*****************************************************************************/
int main(void)
{
/* Initialize chip - handle erratas */
CHIP_Init( );
/* Initialize clocks and oscillators */
cmuSetup( );
/* Initialize UART peripheral */
uartSetup( );
/* Initialize Development Kit in EBI mode */
// BSP_Init(BSP_INIT_DEFAULT);
/* Enable RS-232 transceiver on Development Kit */
//BSP_PeripheralAccess(BSP_RS232_UART, true);
/* When DVK is configured, and no more DVK access is needed, the interface can safely be disabled to save current */
//BSP_Disable();
/* Write welcome message to UART */
uartPutData((uint8_t*) welcomeString, welLen);
/* Eternal while loop
* CPU will sleep during Rx and Tx. When a byte is transmitted, an interrupt
* wakes the CPU which copies the next byte in the txBuf queue to the
* UART TXDATA register.
*
* When the predefined termiation character is received, the all pending
* data in rxBuf is copied to txBuf and echoed back on the UART */
while (1)
{
/* Wait in EM1 while UART transmits */
EMU_EnterEM1();
/* Check if RX buffer has overflowed */
if (rxBuf.overflow)
{
rxBuf.overflow = false;
uartPutData((uint8_t*) overflowString, ofsLen);
}
/* Check if termination character is received */
if (rxBuf.data[(rxBuf.wrI - 1) % BUFFERSIZE] == TERMINATION_CHAR)
{
/* Copy received data to UART transmit queue */
uint8_t tmpBuf[BUFFERSIZE];
int len = uartGetData(tmpBuf, 0);
uartPutData(tmpBuf, len);
}
}
}
/******************************************************************************
* #brief uartSetup function
*
******************************************************************************/
void uartSetup(void)
{
/* Enable clock for GPIO module (required for pin configuration) */
CMU_ClockEnable(cmuClock_GPIO, true);
/* Configure GPIO pins */
GPIO_PinModeSet(gpioPortC, 0, gpioModePushPull, 1);
GPIO_PinModeSet(gpioPortC, 1, gpioModeInput, 0);
/* Prepare struct for initializing UART in asynchronous mode*/
uartInit.enable = usartDisable; /* Don't enable UART upon intialization */
uartInit.refFreq = 0; /* Provide information on reference frequency. When set to 0, the reference frequency is */
uartInit.baudrate = 115200; /* Baud rate */
uartInit.oversampling = usartOVS16; /* Oversampling. Range is 4x, 6x, 8x or 16x */
uartInit.databits = usartDatabits8; /* Number of data bits. Range is 4 to 10 */
uartInit.parity = usartNoParity; /* Parity mode */
uartInit.stopbits = usartStopbits1; /* Number of stop bits. Range is 0 to 2 */
// uartInit.mvdis = false; /* Disable majority voting */
// uartInit.prsRxEnable = false; /* Enable USART Rx via Peripheral Reflex System */
// uartInit.prsRxCh = usartPrsRxCh0; /* Select PRS channel if enabled */
/* Initialize USART with uartInit struct */
USART_InitAsync(uart, &uartInit);
/* Prepare UART Rx and Tx interrupts */
USART_IntClear(uart, _UART_IFC_MASK);
USART_IntEnable(uart, UART_IEN_RXDATAV);
NVIC_ClearPendingIRQ(USART1_RX_IRQn);
NVIC_ClearPendingIRQ(USART1_TX_IRQn);
NVIC_EnableIRQ(USART1_RX_IRQn);
NVIC_EnableIRQ(USART1_TX_IRQn);
/* Enable I/O pins at UART1 location #2 */
uart->ROUTE = UART_ROUTE_RXPEN | UART_ROUTE_TXPEN | UART_ROUTE_LOCATION_LOC0;
/* Enable UART */
USART_Enable(uart, usartEnable);
}
/******************************************************************************
* #brief uartGetChar function
*
* Note that if there are no pending characters in the receive buffer, this
* function will hang until a character is received.
*
*****************************************************************************/
uint8_t uartGetChar( )
{
uint8_t ch;
/* Check if there is a byte that is ready to be fetched. If no byte is ready, wait for incoming data */
if (rxBuf.pendingBytes < 1)
{
while (rxBuf.pendingBytes < 1) ;
}
/* Copy data from buffer */
ch = rxBuf.data[rxBuf.rdI];
rxBuf.rdI = (rxBuf.rdI + 1) % BUFFERSIZE;
/* Decrement pending byte counter */
rxBuf.pendingBytes--;
return ch;
}
/******************************************************************************
* #brief uartPutChar function
*
*****************************************************************************/
void uartPutChar(uint8_t ch)
{
/* Check if Tx queue has room for new data */
if ((txBuf.pendingBytes + 1) > BUFFERSIZE)
{
/* Wait until there is room in queue */
while ((txBuf.pendingBytes + 1) > BUFFERSIZE) ;
}
/* Copy ch into txBuffer */
txBuf.data[txBuf.wrI] = ch;
txBuf.wrI = (txBuf.wrI + 1) % BUFFERSIZE;
/* Increment pending byte counter */
txBuf.pendingBytes++;
/* Enable interrupt on USART TX Buffer*/
USART_IntEnable(uart, UART_IEN_TXBL);
}
/******************************************************************************
* #brief uartPutData function
*
*****************************************************************************/
void uartPutData(uint8_t * dataPtr, uint32_t dataLen)
{
uint32_t i = 0;
/* Check if buffer is large enough for data */
if (dataLen > BUFFERSIZE)
{
/* Buffer can never fit the requested amount of data */
return;
}
/* Check if buffer has room for new data */
if ((txBuf.pendingBytes + dataLen) > BUFFERSIZE)
{
/* Wait until room */
while ((txBuf.pendingBytes + dataLen) > BUFFERSIZE) ;
}
/* Fill dataPtr[0:dataLen-1] into txBuffer */
while (i < dataLen)
{
txBuf.data[txBuf.wrI] = *(dataPtr + i);
txBuf.wrI = (txBuf.wrI + 1) % BUFFERSIZE;
i++;
}
/* Increment pending byte counter */
txBuf.pendingBytes += dataLen;
/* Enable interrupt on USART TX Buffer*/
USART_IntEnable(uart, UART_IEN_TXBL);
}
/******************************************************************************
* #brief uartGetData function
*
*****************************************************************************/
uint32_t uartGetData(uint8_t * dataPtr, uint32_t dataLen)
{
uint32_t i = 0;
/* Wait until the requested number of bytes are available */
if (rxBuf.pendingBytes < dataLen)
{
while (rxBuf.pendingBytes < dataLen) ;
}
if (dataLen == 0)
{
dataLen = rxBuf.pendingBytes;
}
/* Copy data from Rx buffer to dataPtr */
while (i < dataLen)
{
*(dataPtr + i) = rxBuf.data[rxBuf.rdI];
rxBuf.rdI = (rxBuf.rdI + 1) % BUFFERSIZE;
i++;
}
/* Decrement pending byte counter */
rxBuf.pendingBytes -= dataLen;
return i;
}
/***************************************************************************//**
* #brief Set up Clock Management Unit
******************************************************************************/
void cmuSetup(void)
{
/* Start HFXO and wait until it is stable */
/* CMU_OscillatorEnable( cmuOsc_HFXO, true, true); */
/* Select HFXO as clock source for HFCLK */
/* CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO ); */
/* Disable HFRCO */
/* CMU_OscillatorEnable( cmuOsc_HFRCO, false, false ); */
/* Enable clock for HF peripherals */
CMU_ClockEnable(cmuClock_HFPER, true);
/* Enable clock for USART module */
CMU_ClockEnable(cmuClock_USART1, true);
}
/**************************************************************************//**
* #brief UART1 RX IRQ Handler
*
* Set up the interrupt prior to use
*
* Note that this function handles overflows in a very simple way.
*
*****************************************************************************/
void USART1_RX_IRQHandler(void)
{
/* Check for RX data valid interrupt */
if (uart->IF & UART_IF_RXDATAV)
{
/* Copy data into RX Buffer */
uint8_t rxData = USART_Rx(uart);
rxBuf.data[rxBuf.wrI] = rxData;
rxBuf.wrI = (rxBuf.wrI + 1) % BUFFERSIZE;
rxBuf.pendingBytes++;
/* Flag Rx overflow */
if (rxBuf.pendingBytes > BUFFERSIZE)
{
rxBuf.overflow = true;
}
}
}
/**************************************************************************//**
* #brief UART1 TX IRQ Handler
*
* Set up the interrupt prior to use
*
*****************************************************************************/
void USART1_TX_IRQHandler(void)
{
/* Check TX buffer level status */
if (uart->IF & UART_IF_TXBL)
{
if (txBuf.pendingBytes > 0)
{
/* Transmit pending character */
USART_Tx(uart, txBuf.data[txBuf.rdI]);
txBuf.rdI = (txBuf.rdI + 1) % BUFFERSIZE;
txBuf.pendingBytes--;
}
/* Disable Tx interrupt if no more bytes in queue */
if (txBuf.pendingBytes == 0)
{
USART_IntDisable(uart, UART_IEN_TXBL);
}
}
}
I am using FT2232H-56Q. I want to use the SPI channels. I downloaded the libMPSSE-SPI example.
I am using the sample example "sample-static.c". When I run the exe I always get this message:
Press any key to continue . . . Number of available SPI channels = 0
This happens even when the device is connected.
Code:
/*!
* \file sample-static.c
*
* \author FTDI
* \date 20110512
*
* Copyright © 2000-2014 Future Technology Devices International Limited
*
*
* THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* Project: libMPSSE
* Module: SPI Sample Application - Interfacing 94LC56B SPI EEPROM
*
* Rivision History:
* 0.1 - 20110512 - Initial version
* 0.2 - 20110801 - Changed LatencyTimer to 255
* Attempt to open channel only if available
* Added & modified macros
* Included stdlib.h
* 0.3 - 20111212 - Added comments
* 0.41 - 20140903 - Fixed compilation warnings
* Added testing of SPI_ReadWrite()
*/
/******************************************************************************/
/* Include files */
/******************************************************************************/
/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <assert.h>
//#include <vector.h>
#include <stdbool.h>
//#include <random>
/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#endif
/* Include D2XX header*/
#include "ftd2xx.h"
/* Include libMPSSE header */
#include "libMPSSE_spi.h"
/******************************************************************************/
/* Macro and type defines */
/******************************************************************************/
/* Helper macros */
#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
!= FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s(): NULL expression \
encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};
/* Application specific macro definations */
#define SPI_DEVICE_BUFFER_SIZE 256
#define SPI_WRITE_COMPLETION_RETRY 10
#define START_ADDRESS_EEPROM 0x00 /*read/write start address inside the EEPROM*/
#define END_ADDRESS_EEPROM 0x10
#define RETRY_COUNT_EEPROM 10 /* number of retries if read/write fails */
#define CHANNEL_TO_OPEN 0 /*0 for first available channel, 1 for next... */
#define SPI_SLAVE_0 0
#define SPI_SLAVE_1 1
#define SPI_SLAVE_2 2
#define DATA_OFFSET 4
#define USE_WRITEREAD 0
/******************************************************************************/
/* Global variables */
/******************************************************************************/
static FT_HANDLE ftHandle;
static uint8 buffer[SPI_DEVICE_BUFFER_SIZE] = {0};
static FT_DEVICE_LIST_INFO_NODE *devList;
static uint32 numberChannels;
/******************************************************************************/
/* Public function definitions */
/******************************************************************************/
/**
* #brief Initializes the comBridge
* Must be called first
* #param[out] noChannels: Number of available channels
* #param[out] channelId[]: Description of the devices with their index being identical to the channel selector in all other functions
* #return Device status with FT_OK = 0
*/
FT_STATUS comBridge_initialize(uint32 *noChannels, char *channelId[]) {
Init_libMPSSE();
FT_STATUS status = FT_OK;
// get number of channels
status = SPI_GetNumChannels(noChannels);
numberChannels = *noChannels;
APP_CHECK_STATUS(status);
#ifdef VERBOSE
printf("ComBridge initialized\n");
printf(" SPI channels %d\n\n", *noChannels);
#endif // VERBOSE
// get channel infos
devList = (FT_DEVICE_LIST_INFO_NODE *)calloc(*noChannels, sizeof(FT_DEVICE_LIST_INFO_NODE));
for (uint32 channelIndex = 0; channelIndex < *noChannels; channelIndex++) {
status = SPI_GetChannelInfo(channelIndex, devList);
APP_CHECK_STATUS(status);
strcpy(channelId[channelIndex], devList->Description);
#ifdef VERBOSE
printf("Channel %d info\n", channelIndex);
printf(" Flags 0x%x\n", devList->Flags);
printf(" Type 0x%x\n", devList->Type);
printf(" ID 0x%x\n", devList->ID);
printf(" LocId 0x%x\n", devList->LocId);
printf(" SerialNumber %s\n", devList->SerialNumber);
printf(" Description %s\n", devList->Description);
//printf(" ftHandle=0x%x\n", (unsigned int)devList->ftHandle);
printf("\n");
#endif // VERBOSE
};
return status;
}
/**
* #brief Opens and initilizes a SPI channel
* Must be called after comBridge_initialize() and for each channel individually
* Latency = 255 ms, that "xDBUS3 of MPSSE is chip select" and that "chip select is active high" are predefined and cannot be changed manually
* #param[in] channel: Selects a channel via the index of the corresponding element in the channelId[] array
* #param[in] clockRate_Hz: Clock rate of the SPI bus in Hz (0..10 MHz)
* #param[in] spiMode: Selects SPI Mode (SPI_CONFIG_OPTION_MODE0 or SPI_CONFIG_OPTION_MODE3)
* #return Device status with FT_OK = 0
*/
FT_STATUS comBridge_setup(uint32 channel, uint32 clockRate_Hz, uint32 spiMode) {
FT_STATUS status = FT_OK;
assert(channel < numberChannels);
assert(clockRate_Hz <= 10000000);
assert((spiMode == SPI_CONFIG_OPTION_MODE0) | (spiMode == SPI_CONFIG_OPTION_MODE3));
status = SPI_OpenChannel(channel, &devList[channel].ftHandle);
APP_CHECK_STATUS(status);
ChannelConfig channelConf = {
5000, // ClockRate
255, // LatencyTime
SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3 | SPI_CONFIG_OPTION_CS_ACTIVELOW, // configOptions
0x00000000 // Pin
};
channelConf.ClockRate = clockRate_Hz;
channelConf.configOptions = spiMode | SPI_CONFIG_OPTION_CS_DBUS3 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
status = SPI_InitChannel(devList[channel].ftHandle, &channelConf);
APP_CHECK_STATUS(status);
#ifdef VERBOSE
printf("Channel %d opened\n", channel);
printf(" ClockRate %d\n", channelConf.ClockRate);
printf(" Latency %d\n", channelConf.LatencyTimer);
printf(" Config %d\n", channelConf.configOptions);
printf(" Pin %d\n\n", channelConf.Pin);
//printf(" Handle=%ld\n", (uint32)devList[channel].ftHandle);
#endif // VERBOSE
// sets all GPIO pins as input
status = FT_WriteGPIO(devList[channel].ftHandle, 0b00000000, 0b00000000);
APP_CHECK_STATUS(status);
return status;
}
/*!
* \brief Writes to EEPROM
*
* This function writes a byte to a specified address within the 93LC56B EEPROM
*
* \param[in] slaveAddress Address of the I2C slave (EEPROM)
* \param[in] registerAddress Address of the memory location inside the slave to where the byte
* is to be written
* \param[in] data The byte that is to be written
* \return Returns status code of type FT_STATUS(see D2XX Programmer's Guide)
* \sa Datasheet of 93LC56B http://ww1.microchip.com/downloads/en/DeviceDoc/21794F.pdf
* \note
* \warning
*/
static FT_STATUS read_byte(uint8 slaveAddress, uint8 address, uint16 *data)
{
uint32 sizeToTransfer = 0;
uint32 sizeTransfered;
uint8 writeComplete=0;
uint32 retry=0;
FT_STATUS status;
/* CS_High + Write command + Address */
sizeToTransfer=1;
sizeTransfered=0;
buffer[0] = 0xC0;/* Write command (3bits)*/
buffer[0] = buffer[0] | ( ( address >> 3) & 0x0F );/*5 most significant add bits*/
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
APP_CHECK_STATUS(status);
/*Write partial address bits */
sizeToTransfer=4;
sizeTransfered=0;
buffer[0] = ( address & 0x07 ) << 5; /* least significant 3 address bits */
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS);
APP_CHECK_STATUS(status);
/*Read 2 bytes*/
sizeToTransfer=2;
sizeTransfered=0;
status = SPI_Read(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
APP_CHECK_STATUS(status);
*data = (uint16)(buffer[1]<<8);
*data = (*data & 0xFF00) | (0x00FF & (uint16)buffer[0]);
return status;
}
/*!
* \brief Reads from EEPROM
*
* This function reads a byte from a specified address within the 93LC56B EEPROM
*
* \param[in] slaveAddress Address of the I2C slave (EEPROM)
* \param[in] registerAddress Address of the memory location inside the slave from where the
* byte is to be read
* \param[in] *data Address to where the byte is to be read
* \return Returns status code of type FT_STATUS(see D2XX Programmer's Guide)
* \sa Datasheet of 93LC56B http://ww1.microchip.com/downloads/en/DeviceDoc/21794F.pdf
* \note
* \warning
*/
static FT_STATUS write_byte(uint8 slaveAddress, uint8 address, uint16 data)
{
uint32 sizeToTransfer = 0;
uint32 sizeTransfered=0;
uint8 writeComplete=0;
uint32 retry=0;
FT_STATUS status;
/* Write command EWEN(with CS_High -> CS_Low) */
sizeToTransfer=11;
sizeTransfered=0;
buffer[0]=0x9F;/* SPI_EWEN -> binary 10011xxxxxx (11bits) */
buffer[1]=0xFF;
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
APP_CHECK_STATUS(status);
/* CS_High + Write command + Address */
sizeToTransfer=1;
sizeTransfered=0;
buffer[0] = 0xA0;/* Write command (3bits) */
buffer[0] = buffer[0] | ( ( address >> 3) & 0x0F );/*5 most significant add bits*/
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
APP_CHECK_STATUS(status);
/*Write 3 least sig address bits */
sizeToTransfer=3;
sizeTransfered=0;
buffer[0] = ( address & 0x07 ) << 5; /* least significant 3 address bits */
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS);
APP_CHECK_STATUS(status);
/* Write 2 byte data + CS_Low */
sizeToTransfer=2;
sizeTransfered=0;
buffer[0] = (uint8)(data & 0xFF);
buffer[1] = (uint8)((data & 0xFF00)>>8);
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
APP_CHECK_STATUS(status);
/* Wait until D0 is high */
#if 1
/* Strobe Chip Select */
sizeToTransfer=0;
sizeTransfered=0;
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
APP_CHECK_STATUS(status);
#ifndef __linux__
Sleep(10);
#endif
sizeToTransfer=0;
sizeTransfered=0;
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
APP_CHECK_STATUS(status);
#else
retry=0;
state=FALSE;
SPI_IsBusy(ftHandle,&state);
while((FALSE==state) && (retry<SPI_WRITE_COMPLETION_RETRY))
{
printf("SPI device is busy(%u)\n",(unsigned)retry);
SPI_IsBusy(ftHandle,&state);
retry++;
}
#endif
/* Write command EWEN(with CS_High -> CS_Low) */
sizeToTransfer=11;
sizeTransfered=0;
buffer[0]=0x8F;/* SPI_EWEN -> binary 10011xxxxxx (11bits) */
buffer[1]=0xFF;
status = SPI_Write(ftHandle, buffer, sizeToTransfer, &sizeTransfered,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
APP_CHECK_STATUS(status);
return status;
}
/*!
* \brief Main function / Entry point to the sample application
*
* This function is the entry point to the sample application. It opens the channel, writes to the
* EEPROM and reads back.
*
* \param[in] none
* \return Returns 0 for success
* \sa
* \note
* \warning
*/
int main()
{
uint32 noChannels = 0;
char *channelId[10];
char channelIdArray[10][46] = { { '\0' } };
for (int i = 0; i < sizeof(channelId); i++)
channelId[i] = channelIdArray[i];
comBridge_initialize(&noChannels, channelId);
for (uint32 channel = 0; channel < noChannels; channel++)
{
//cout << "Channel " << channel << ": " << channelId[channel] << endl;
comBridge_setup(channel, 100000, SPI_CONFIG_OPTION_MODE0);
comBridge_release(channel);
}
FT_STATUS status = FT_OK;
FT_DEVICE_LIST_INFO_NODE devList = {0};
ChannelConfig channelConf = {0};
uint8 address = 0;
uint32 channels = 0;
uint16 data = 0;
uint8 i = 0;
uint8 latency = 255;
channelConf.ClockRate = 5000;
channelConf.LatencyTimer = latency;
channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3;// | SPI_CONFIG_OPTION_CS_ACTIVELOW;
channelConf.Pin = 0x00000000;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/
/* init library */
#ifdef _MSC_VER
Init_libMPSSE();
#endif
status = SPI_GetNumChannels(&channels);
APP_CHECK_STATUS(status);
printf("Number of available SPI channels = %d\n",(int)channels);
if(channels>0)
{
for(i=0;i<channels;i++)
{
status = SPI_GetChannelInfo(i,&devList);
APP_CHECK_STATUS(status);
printf("Information on channel number %d:\n",i);
/* print the dev info */
printf(" Flags=0x%x\n",devList.Flags);
printf(" Type=0x%x\n",devList.Type);
printf(" ID=0x%x\n",devList.ID);
printf(" LocId=0x%x\n",devList.LocId);
printf(" SerialNumber=%s\n",devList.SerialNumber);
printf(" Description=%s\n",devList.Description);
printf(" ftHandle=0x%x\n",(unsigned int)devList.ftHandle);/*is 0 unless open*/
}
/* Open the first available channel */
status = SPI_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
APP_CHECK_STATUS(status);
printf("\nhandle=0x%x status=0x%x\n",(unsigned int)ftHandle,status);
status = SPI_InitChannel(ftHandle,&channelConf);
APP_CHECK_STATUS(status);
#if USE_WRITEREAD
{
uint8 k,l;
uint8 inBuffer[100];
uint8 outBuffer[]={0x81,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,30,31,32,33,34,35,36,37,38,39};
uint32 sizeToTransfer,sizeTransferred;
for(k=0; k<5; k++)
{
printf("LoopCount = %u ",(unsigned)k);
sizeToTransfer=10;
sizeTransferred=0;
#if 1 // BYTES
status = SPI_ReadWrite(ftHandle, inBuffer, outBuffer+k, sizeToTransfer, &sizeTransferred,
SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
#else // BITES
status = SPI_ReadWrite(ftHandle, inBuffer, outBuffer+k, sizeToTransfer*8, &sizeTransferred,
SPI_TRANSFER_OPTIONS_SIZE_IN_BITS|
SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE|
SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE);
#endif
APP_CHECK_STATUS(status);
printf("status=0x%x sizeTransferred=%u\n", status, sizeTransferred);
for(l=0;l<sizeToTransfer;l++)
printf("0x%x\n",(unsigned)inBuffer[l]);
printf("\n");
}
}
#else // USE_WRITEREAD
for(address=START_ADDRESS_EEPROM;address<END_ADDRESS_EEPROM;address++)
{
printf("writing address = %02d data = %d\n",address,address+DATA_OFFSET);
write_byte(SPI_SLAVE_0, address,(uint16)address+DATA_OFFSET);
}
for(address=START_ADDRESS_EEPROM;address<END_ADDRESS_EEPROM;address++)
{
read_byte(SPI_SLAVE_0, address,&data);
printf("reading address = %02d data = %d\n",address,data);
}
#endif // USE_WRITEREAD
status = SPI_CloseChannel(ftHandle);
}
#ifdef _MSC_VER
Cleanup_libMPSSE();
#endif
#ifndef __linux__
system("pause");
#endif
return 0;
}
I also have the same problem with FT2232H / win7Pro.
The root cause is libMPSSE get wrong locID and judge that the device is not available since D2XX always returns LocId=0 to libMPSSE.
ftdi_mid.c
case FT_DEVICE_2232H:
if(((devList.LocId & 0xf)==1)|| ((devList.LocId & 0xf)==2))
{
isMPSSEAvailable = MID_MPSSE_AVAILABLE;
}
break;
I modify the condition and re-compile libMPSSE with mingw64. It just works.
I had a similar problem on Ubuntu 19.10. The root cause of this was the kernel module that was interacting with FTDI once it was connected and preventing me to connect with it.
The solution was to unload that kernel module:
sudo rmmod ftdi_sio
It is also mentioned in the libftd2xx ReadMe file:
If the message "FT_Open failed" appears:
Perhaps the kernel automatically loaded another driver for the
FTDI USB device.
sudo lsmod
If "ftdi_sio" is listed:
Unload it (and its helper module, usbserial), as follows.
sudo rmmod ftdi_sio
sudo rmmod usbserial
Otherwise, it's possible that libftd2xx does not recognise your
device's Vendor and Product Identifiers. Call FT_SetVIDPID before
calling FT_Open/FT_OpenEx/FT_ListDevices.
I've wrote a letter to FTDI Chip with the question. The support send an updated library that works. The version of library is 0.6 (beta).
I'm currently doing a project, using RL78G14 as microcontroller. The project involves making an IR remote and control panel. If been trying to write code to setup a UART. I get an few warning messages of passing an incompatible pointer type when passing TxBuf and RxBuf, and my UART doesn't seem to work. Can anyone help me with the code?
void main(void)
{
R_MAIN_UserInit();
uart1Status = R_UART1_Receive(&RxBuf[0],1); // Prime UART1 Rx
while (1U)
{
//Check if byte received on UART
if (RxFlag)
{
// clear rx flag
RxFlag = 0U;
//Echo back the received character
TxBuf[0] = RxBuf[0];
//Send TX buffer, and specify how many characters to write
uart1Status = R_UART1_Send(TxBuf,1);
// re-Prime UART Rx
uart1Status = R_UART1_Receive(RxBuf,1);
}
//If a character has been transmitted
if (TxFlag)
{
// End of UART2 transmit
TxFlag = 0U; // clear tx flag
}
}
/***********************************************************************************************************************
* Function Name: R_UART1_Receive
* Description : This function receives UART1 data.
* Arguments : rx_buf -
* receive buffer pointer
* rx_num -
* buffer size
* Return Value : status -
* MD_OK or MD_ARGERROR
***********************************************************************************************************************/
MD_STATUS R_UART1_Receive(uint8_t * const rx_buf, uint16_t rx_num)
{
MD_STATUS status = MD_OK;
if (rx_num < 1U)
{
status = MD_ARGERROR;
}
else
{
g_uart1_rx_count = 0U;
g_uart1_rx_length = rx_num;
gp_uart1_rx_address = rx_buf;
}
return (status);
}
/***********************************************************************************************************************
* Function Name: R_UART1_Send
* Description : This function sends UART1 data.
* Arguments : tx_buf -
* transfer buffer pointer
* tx_num -
* buffer size
* Return Value : status -
* MD_OK or MD_ARGERROR
***********************************************************************************************************************/
MD_STATUS R_UART1_Send(uint8_t * const tx_buf, uint16_t tx_num)
{
MD_STATUS status = MD_OK;
if (tx_num < 1U)
{
status = MD_ARGERROR;
}
else
{
gp_uart1_tx_address = tx_buf;
g_uart1_tx_count = tx_num;
STMK1 = 1U; /* disable INTST1 interrupt */
TXD1 = *gp_uart1_tx_address;
gp_uart1_tx_address++;
g_uart1_tx_count--;
STMK1 = 0U; /* enable INTST1 interrupt */
}
return (status);
}
If you are using development board, R11 Pin check. It is connected to CAN RXD chip TJA1050T, and hence not receiving any data. Cut R11 jumper and it will start working.
Did you Started UART1 ? need to start it in Initialization.
I am running a C program on an AVR chip. Whenever a serial signal is heard, it runs the serial interrupt ISR (USART_RX_vect). In this method it should turn on change to = 1;. Then in my main while loop, it should clear the LCD and display it and then set change = 0 again.
This is to stop it continually doing the calulations, and displaying the result on the LCD a million times a minute..
However, when the interrupt method changes the change variable to 1, it does not seem to change it "globally" and in the main method it is always 0..
There is a bit of stuff in here that is for debugging purposes.
/* LCD DEFINES */
#define LED PB5
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
/* UART SERIAL DEFINES */
#define F_CPU 16000000UL
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1
#define STARTCHAR 'R'
#define ENDCHAR 'E'
char reading;
char inputBuffer[12];
char readStatus;
uint8_t position;
int change;
char output;
int result;
struct Axis
{
uint8_t axisNumber;
uint16_t position;
uint16_t oldPosition;
} axis1, axis2, axis3;
/* SETUP UART */
void USART_Init( unsigned int ubrr)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void USART_Transmit( unsigned char data )
{
UDR0 = data;
}
unsigned char USART_Receive( void )
{
return UDR0;
}
/*****************************************************************/
int main(void)
{
/* INITALISE SERIAL */
USART_Init(MYUBRR);
/* Turn on Receive Complete Interrupt */
UCSR0B |= (1 << RXCIE0);
/* Turn On GLobal Interrupts */
sei();
position = 0;
change = 0;
/* Initialise LCD */
lcd_init(LCD_DISP_ON); /* Initialize display, cursor off. */
lcd_clrscr();
lcd_puts("READY");
//Turn on LED 13
set_output(PORTB,LED);
output_low(PORTB,LED);
while (1) /* Loop forever */
{
if (change == 1)
{
//If not reading, display the result on the LCD display.
axis1.position = (inputBuffer[0]<< 8) | inputBuffer[1];
axis2.position = (inputBuffer[2]<< 8) | inputBuffer[3];
axis3.position = (inputBuffer[4]<< 8) | inputBuffer[5];
char axis1Printout[12];
char axis2Printout[12];
char axis3Printout[12];
sprintf(axis1Printout,"%u ", axis1.position);
sprintf(axis2Printout,"%u ", axis2.position);
sprintf(axis3Printout,"%u ", axis3.position);
char output[40] = "";
strcat(output, axis1Printout);
strcat(output, axis2Printout);
//strcat(output, axis3Printout);
lcd_clrscr(); /* Clear the screen*/
lcd_puts(output);
_delay_ms(300);
change = 0;
}
}
}
/* INTERRUPTS */
ISR (USART_RX_vect)
{
change = 1;
unsigned char input = USART_Receive();
if (input == 'R')
{
readStatus = 0; //Reading
position = 0;
}
else if ((input != 'E') && (position < 12) && (position > -1))
{
inputBuffer[position] = input;
position++;
}
else if (input == 'E')
{
readStatus = 1; //Stop Reading
position = -1;
output_high(PORTB,LED);
}
}
You need to declare change using the volatile keyword:
volatile int change;
This tells the two 'threads' (main execution loop and your ISR code) to not 'cache' the value in a register, but always retrieve it from memory.
Edit: There's another problem with the code - in your main loop, by the time you set changed to 0, you may have already had another interrupt which should have triggered your loop to run again. The easy-but-not-guaranteed fix is to immediately set changed to 0 straight after you check it. The proper way would be to use a lock - but depending on your situation, the first option might do.
Make the variable declaration volatile to ensure that a changed value is written imediately to the variable in memory.
An object shared by an interrupt handler and the application code should be qualified as volatile in the declaration.
Without the qualifier, the implementation can assume the object cannot change unexpectedly in the application code and can cache the variable (in a register for example) for optimizations while executing the application code.