I am trying to configure a GPIO pin as output but it is failing with the reason of device or resource busy. The pin is configured as output, open-drain and belongs to the group of gpiochip24 at offset 3. On reading the information from line info IOCTL I can see that the flag is 3 (OPEN_DRAIN) and is assigned a consumer. But when I try to configure the pin as output with a default value using the GPIO_GET_LINEHANDLE_IOCTL, the IOCTL fails.
int gpioFd = open("/dev/gpiochip24", 0);
if (gpioFd < 0) {
printf("ERROR: GPIO chip fail\n");
return -1;
}
struct gpiohandle_request req;
req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
req.lineoffsets[0] = 3;
req.lines = 1;
req.default_values[0] = 0;
strcpy(req.consumer_label, "P_EN");
int lhfd = ioctl(gpioFd, GPIO_GET_LINEHANDLE_IOCTL, &req);
if(lhfd < 0)
{
int err = errno;
printf("Error No: %d\n", err);
printf("ERROR: Gpio Line handle\n");
return -1;
}
Output:
Error No: 16
ERROR: Gpio Line handle
I looked inside /sys/kernel/debug/gpio to understand who is using the resource but I get the following response:
gpiochip24: GPIOs 99-106, parent: platform/139b0000.pinctrl, gpg2
How do I resolve this error of device busy?
Because req is local, it has garbage when allocated, and it doesn't look like the code is initializing it properly, and - in particular - the flags value probably has junk in it.
req.flags |= GPIOHANDLE_REQUEST_OUTPUT; // no
req.flags = GPIOHANDLE_REQUEST_OUTPUT; // yes
would work around this particular issue, but be sure all the other fields in this structure are not relying on junk.
Related
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 am writing a C program in Visual Studio 2013 to send MIDI data to a MIDI device over a serial (COM) port. My code thus far is as follows:
Opening the serial/COM port:
unsigned int SERIALCOMMS_OpenPort(HANDLE *hSerialPort,
unsigned int comPortNum,
unsigned int baudRate)
{
DCB dcbSerialParams = {0};
COMMTIMEOUTS timeouts = {0};
unsigned char portStr[COM_PORT_LEN_MAX];
/* Initialisations */
memset(portStr, 0x00, sizeof(portStr));
/* Construct the COM port string */
sprintf(portStr, "%sCOM%d", COM_PORT_PREFIX, comPortNum);
printf("Opening serial port...");
*hSerialPort = CreateFile((LPCSTR)portStr,
(GENERIC_READ | GENERIC_WRITE),
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (*hSerialPort == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
printf("\nError: \nThe system cannot find the file specified (%s)\n", portStr);
return 1;
}
else if (GetLastError() == ERROR_INVALID_NAME)
{
printf("\nError: \n%s port name syntax is incorrect'\n", portStr);
return 1;
}
else
{
printf("\nHandle creation error code: %x\n", GetLastError());
return 1;
}
puts("\t...CreateFile returned an invalid handle value");
}
printf("OK\n");
/* Set device parameters */
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (GetCommState(*hSerialPort, &dcbSerialParams) == 0)
{
printf("Error getting device state\n");
CloseHandle(*hSerialPort);
return 1;
}
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (SetCommState(*hSerialPort, &dcbSerialParams) == 0)
{
printf("Error setting device parameters\n");
return 1;
}
/* Set COM port timeout settings */
timeouts.ReadIntervalTimeout = 50;
timeouts.ReadTotalTimeoutConstant = 50;
timeouts.ReadTotalTimeoutMultiplier = 10;
timeouts.WriteTotalTimeoutConstant = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;
if (SetCommTimeouts(*hSerialPort, &timeouts) == 0)
{
printf("Error setting timeouts\n");
return 1;
}
return 0;
}
The constant COM_PORT_PREFIX is defined as follows:
#define COM_PORT_PREFIX "\\\\\.\\"
The port opens fine. However, when I send data to it, it seems that the received data is much different than what is supposed to be sent. I am testing this with an Arduino that is programmed to spool out the received data as integer/hex values, for purposes of testing what is actually being sent by the PC.
Here is the code of the function used to send the data:
unsigned int SERIALCOMMS_Send(HANDLE hSerialPort,
unsigned char *txData,
unsigned int *byteCount)
{
unsigned int bytesWritten = 0u;
/* Transmit data */
if (!WriteFile(hSerialPort, txData, *byteCount, &bytesWritten, NULL))
{
printf("Error transmitting data\n");
return 1;
}
printf("\n%d bytes written\n", bytesWritten);
return 0;
}
Using the following method with the above "Send" function:
unsigned int byteCount = 1u;
unsigned char dataByte[1];
SERIALCOMMS_Send(hSerialPort, dataByte, &byteCount);
When I send the following MIDI data (hex values), it gets received as follows:
0x91 gets received as 0xC9
0x92 gets received as 0xC8
0x93 gets received as 0xC9
0x94 gets received as 0xCA
0x95 gets received as 0xCB
0x24 gets received as 0xD2
Clearly, nothing of this makes sense. I am unable to figure out what is causing this. Some of the project properties in Visual Studio are configured as follows:
Project settings
One possible aspect might be the specified character set (currently set as "Use Multi-Byte Character Set"). If I change this to "Use Unicode Character Set", then the program is unable to connect with the COM port.
Thinking logically of the problem, it must have to do with the way I am sending the data. I am most probably passing the MIDI data to be sent in the wrong manner, but I honestly cannot figure out what is causing the problem and what I am doing wrong.
Any help will be greatly appreciated.
UPDATE:
The baud rate is set at 31250 bps (as per MIDI standard) on both the PC and the Arduino.
It seems that according to this answer on another thread on stackoverflow it is not that simple to just use non-standard baud rates on the Windows platform due to the crystal oscillation frequency used in PCs for calculating the UART baud rates and the way the baud rates are derived therefrom. Thus it seems that it is best to stick to standard baud rates.
Using a standard baud rate solved my problem. However, it thus enforces a change in the specifications on the hardware used in my case, which is not ideal.
This, of course, raises the following question - what does one have to do to be able to use non-standard baud rates? Would one have to write an additional/custom driver for that?
I am using a custom development board with a Zynq XC72010 used to run a Linux 4.5 kernel. I am developing a device driver for a chip we are testing in house and I am having a lot of issues trying to bind a GPIO line to a software IRQ. So far I have tried a few methods and exhausted any google search I can think of. The relevant parts of my devicetree configuration:
/ {
compatible = "xlnx,zynq-7000";
amba {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
ranges;
intc: interrupt-controller#f8f01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xF8F01000 0x1000>,
<0xF8F00100 0x100>;
};
i2c0: i2c#e0004000 {
compatible = "cdns,i2c-r1p10";
status = "disabled";
clocks = <&clkc 38>;
interrupt-parent = <&intc>;
interrupts = <0 25 4>;
reg = <0xe0004000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
// I WANT INTERRUPT TO TRIGGER
// ON THIS DEVICE (axi_gpio_0, pin 2)
device: device#48 {
compatible = "device,name";
reg = <0x48>;
reset-gpios = <&axi_gpio_0 1 0>;
interrupt-parent = <&axi_gpio_0>;
interrupt-gpios = <&axi_gpio_0 2 0>;
};
};
};
amba_pl {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;
axi_gpio_0: gpio#41200000 {
#gpio-cells = <2>;
compatible = "xlnx,xps-gpio-1.00.a";
gpio-controller;
interrupt-parent = <&intc>;
interrupts = <0 31 4>;
reg = <0x41200000 0x10000>;
xlnx,all-inputs = <0x0>;
xlnx,all-inputs-2 = <0x0>;
xlnx,all-outputs = <0x0>;
xlnx,all-outputs-2 = <0x0>;
xlnx,dout-default = <0x00000000>;
xlnx,dout-default-2 = <0x00000000>;
xlnx,gpio-width = <0x10>;
xlnx,gpio2-width = <0x20>;
xlnx,interrupt-present = <0x1>;
xlnx,is-dual = <0x0>;
xlnx,tri-default = <0xFFFFFFFF>;
xlnx,tri-default-2 = <0xFFFFFFFF>;
};
};
I am trying to assign an interrupt to pin 2 of 'axi_gpio_0' inside of 'device'.
Browsing google yielded 3 common methods for binding the interrupt in driver code:
/* Method 1 */
device->interrupt_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"interrupt", GPIOD_IN);
if(IS_ERR(device->interrupt_gpio))
return PTR_ERR(device->interrupt_gpio);
printk("device: Interrupt GPIO = %d\n",desc_to_gpio(device->interrupt_gpio));
irq = gpiod_to_irq(device->interrupt_gpio);
printk("device: IRQ = %d\n",irq);
ret = devm_request_threaded_irq(&i2c_client->dev, irq,
NULL, device_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
"device", device);
if (ret != 0)
dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
/* Method 2 */
device->interrupt_gpio = devm_gpiod_get_optional(&i2c_client->dev,
"interrupt", GPIOD_ASIS);
if (IS_ERR(device->interrupt_gpio))
return PTR_ERR(device->interrupt_gpio);
if (device->interrupt_gpio) {
dev_info(&i2c_client->dev, "Found interrupt GPIO: %d\n",desc_to_gpio(device->interrupt_gpio));
dev_info(&i2c_client->dev, "IRQ Number: %d\n",gpiod_to_irq(device->interrupt_gpio));
gpio_request(desc_to_gpio(device->interrupt_gpio), "DEVICE_INT"); // Request a GPIO pin from the driver
gpio_direction_input(desc_to_gpio(device->interrupt_gpio)); // Set GPIO as input
gpio_set_debounce(desc_to_gpio(device->interrupt_gpio), 50); // Set a 50ms debounce, adjust to your needs
gpio_export(desc_to_gpio(device->interrupt_gpio), false); // The GPIO will appear in /sys/class/gpio
ret = request_irq(gpiod_to_irq(device->interrupt_gpio), // requested interrupt
(irq_handler_t) irqHandler, // pointer to handler function
IRQF_TRIGGER_RISING, // interrupt mode flag
"DEVICE_IRQ_HANDLER", // used in /proc/interrupts
NULL); // the *dev_id shared interrupt lines, NULL is okay
if (ret != 0) {
dev_err(&i2c_client->dev,
"Failed to request IRQ: %d\n", ret);
}
}
else {
dev_err(&i2c_client->dev, "Failed to get interrupt GPIO pin\n");
}
/* Method 3 */
dev_info(&i2c_client->dev, "IRQ requested: %d\n", i2c_client->irq);
ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq,
NULL, device_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW,
"device", device);
if (ret != 0)
dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
I tried combinations of all of these methods and various devicetree configurations, but none of them achieved the functionality I need.
Method 1 results in this output:
device: Interrupt GPIO = 892
device: IRQ = -6
device 0-0048: Failed to request IRQ: -22
Method 2 results in this output:
device 0-0048: Found interrupt GPIO: 892
device 0-0048: IRQ Number: -6
device 0-0048: Failed to request IRQ: -22
So, trying to use the descriptor GPIO and the old GPIO api's are both unsuccessful in binding an interrupt.
To try method 3, I tweaked the devicetree:
device: device#48 {
compatible = "device,name";
reg = <0x48>;
interrupt-parent = <&axi_gpio_0>; // or <&intc>?
interrupts = <0 2 0x02>; // trying to grab pin 2
};
Method 3 results in this output:
genirq: Setting trigger mode 2 for irq 168 failed (gic_set_type+0x0/0x48)
device 0-0048: IRQ requested: 168
genirq: Setting trigger mode 8 for irq 168 failed (gic_set_type+0x0/0x48)
device 0-0048: Failed to request IRQ: -22
It seems the problem is assigning a software interrupt to a specific GPIO in Linux. I don't see what I'm missing here. Any advice is appreciated.
EDIT 1:
I found out that Linux doesn't like low-level interrupts for whatever reason. Changing method 3 to:
device: device#48 {
compatible = "device,name";
reg = <0x48>;
interrupt-parent = <&axi_gpio_0>;
interrupts = <0 2 0x04>;
};
And driver code to:
dev_info(&i2c_client->dev, "IRQ requested: %d\n", i2c_client->irq);
ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq,
NULL, device_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
"device", device);
if (ret != 0)
dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret);
allows me to successfully request an IRQ. However, my signal is active low, so this doesn't really help me much. Also, I'm not sure that this method is referencing axi_gpio_0 pin 2 as the interrupt signal. I can use both intc and axi_gpio_0 as interrupt-parent and it maps to the same IRQ number (I see this from cat /proc/interrupts). So, ignoring the polarity of the signal, how do I make sure that my registered interrupt is triggered based on the toggling of axi_gpio_0 pin 2?
EDIT 2:
I traced the issue with requesting an active-low interrupt to the driver for the interrupt controller: kernel/drivers/irqchip/irq-gic.c. This section of code is what causes the problem:
static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d);
/* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16)
return -EINVAL;
/* SPIs have restrictions on the supported types */
if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
return gic_configure_irq(gicirq, type, base, NULL);
}
Hacking the kernel is not at all what I want to do, but commenting out:
/* SPIs have restrictions on the supported types */
/*if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;*/
allows me to request an active-low interrupt. For testing purposes, this should work temporarily.
UPDATE:
I have successfully created an IRQ on a GPIO pin. My problem was with the GPIO controller I was using. The controller was a Xilinx IP block inside of the Zynq Programmable Logic block and this controller is unable to trigger interrupts on GPIO pins (for reasons unknown to me). I soldered the interrupt pin on the board I was working on to a GPIO pin on a different, more generic controller and now Linux is playing nicely with me.
To summarize, a GPIO controller that matches compatible = "xlnx,xps-gpio-1.00.a"; is unable to bind to software interrupts in Linux. If you have this problem, USE A DIFFERENT GPIO CONTROLLER.
Thanks everyone for the help.
Using the device tree node of method 3, you should be able to retrieve the IRQ using irq_of_parse_and_map(i2c_client->dev.of_node, 0).
The retrieved IRQ can then be requested as you have done it with devm_request_threaded_irq().
I am using an RN42-XV bluetooth module to send characters to the PIC24F from a computer.
The module is connected/paired correctly and the characters that are sent across are also correct (used an oscilloscope).
This is how it is being initialized:
void initUART(){
//Peripheral Pin Mapping
RPINR19bits.U2RXR = 5; //pin 14 UART Receive
RPOR5bits.RP11R = 3; //pin 17 UART Transmit
//Configuring the UART
U2BRG = BRGVAL;
U2MODEbits.UARTEN = 1;
U2MODEbits.UEN = 0;
U2MODEbits.PDSEL = 0;// 8 bit no parity
U2MODEbits.STSEL = 0; // 1 stop bit
U2STAbits.UTXEN = 0;
U2STAbits.URXISEL = 0;
//Putting the UART interrupt flag down.
IFS1bits.U2RXIF = 0;
}
I am also using this function to get the contents of the buffer:
int waitForChar(){
int receivedChar;
// Use the UART RX interrupt flag to wait until we recieve a character.
while(IFS1bits.U2RXIF == 1){
// Clear the UART RX interrupt flag to we can detect the reception
// of another character.
IFS1bits.U2RXIF = 0;
// U2RXREG stores the last character received by the UART. Read this
// value into a local variable before processing.
receivedChar = U2RXREG;
}
return receivedChar;
}
The problem is that the program never goes into the while loop inside the function waitForChar() because the UART interrupt flag is never raised by the hardware.
I have tried different PIC24Fs but all run into the same issue.
The function type is declared as void so it does not return anything. You should be getting compiler warning if you try to assign its return value. Moreover it does not wait for a char. It is "non blocking" that is it returns anyway, but you need a return value to tell you whether it has a char or whether it does a not. If you want it to wait and return a char, it could be like this
int waitForChar(){ // declare a return type
int receivedChar;
while(IFS1bits.U2RXIF == 0); // wait
receivedChar = U2RXREG;
IFS1bits.U2RXIF = 0; // clear status
return receivedChar;
}
I notice a couple of things:
you enable the module (UARTEN) before entirely configuring it.
Shouldn't U2STA.URXDA used as flag to test for receiving?
You don't configure several bits in both registers. That is ok though if you are absolutely sure the startup state is what you like.
The UART initialization code was missing this line:
AD1PCFG = 0xFFFF
The ADC flags have priority over UART. This line disables them.
I am trying to write a device code for C8051F340 to get the data from the host(PC) via USB. I have some example from silicon lab and the code look like below:
void Receive_File(void)
{
ReadStageLength = ((BytesToRead - BytesRead) > MAX_BLOCK_SIZE_READ)? MAX_BLOCK_SIZE_READ:(BytesToRead - BytesRead);
BytesRead += Block_Read((U8*)(&TempStorage[BlockIndex]), ReadStageLength); // Read Block
BlockIndex++;
// If device has received as many bytes as fit on one FLASH page, disable interrupts,
// write page to flash, reset packet index, enable interrupts
// Send handshake packet 0xFF to host after FLASH write
if ((BlockIndex == (BLOCKS_PR_PAGE)) || (BytesRead == BytesToRead))
{
Page_Erase((U8*)(PageIndices[PageIndex]));
Page_Write((U8*)(PageIndices[PageIndex]));
PageIndex++;
Led1 = !Led1;
BlockIndex = 0;
Buffer[0] = 0xFF;
Block_Write(Buffer, 1); // Send handshake Acknowledge to host
}
// Go to Idle state if last packet has been received
if (BytesRead == BytesToRead) {M_State = ST_IDLE_DEV; Led1 = 0;}
}
// Startup code for SDCC to disablt WDT before initializing variables so that
// a reset does not occur
#if defined SDCC
void _sdcc_external_startup (void)
{
PCA0MD &= ~0x40; // Disable Watchdog timer
}
#endif
I have some questions want to ask:
1. Where the data goes? the Buffer [0]?
2. if I got a Hex value transfer from the host, can I just read the Buffer [0] to get it ?
sorry I am a newbie.
Thank you.
Your received data stored in array TempStorage
You used Buufer[0] (the value 0xFF) for to send data to host