BBB - Trouble getting second SPI chip select with device tree - c

I have trouble to get second chip select working on the Beaglebone Black.
I used the .dts given in /lib/firmware with my distribution (Angstrom, kernel 3.8.13) :
/*
* Copyright (C) 2013 CircuitCo
*
* Virtual cape for SPI1 on connector pins P9.29 P9.31 P9.30 P9.28
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/dts-v1/;
/plugin/;
/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";
/* identification */
part-number = "BB-SPI1-01";
version = "00A0";
/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P9.31", /* spi1_sclk */
"P9.29", /* spi1_d0 */
"P9.30", /* spi1_d1 */
"P9.28", /* spi1_cs0 */
"P9.42", /* spi1_cs1 */
/* the hardware ip uses */
"spi1";
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
/* default state has all gpios released and mode set to uart1 */
bb_spi1_pins: pinmux_bb_spi1_pins {
pinctrl-single,pins = <
0x190 0x13 /* mcasp0_aclkx.spi1_sclk, OUTPUT_PULLUP | MODE3 */
0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */
0x164 0x12 /* eCAP0_in_PWM0_out.spi1_cs1 OUTPUT_PULLUP | MODE2 */
>;
};
};
};
fragment#1 {
target = <&spi1>; /* spi1 is numbered correctly */
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bb_spi1_pins>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio4 17 0>, <&gpio1 7 0>;
spi1_0{
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
reg = <0>;
spi-max-frequency = <16000000>;
};
spi1_1{
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
reg = <1>;
spi-max-frequency = <16000000>;
};
};
};
};
I compiled it with dtc and activate it with uEnv.txt :
capemgr.enable_partno=BB-SPI1-01
(Both HDMI and HDMIN capes are disabled)
I have the twos SPI device shown in /dev/ :
/dev/spidev2.0 /dev/spidev2.1
and the pins are used by the spi interface as shown :
root#beaglebone:~# cat $PINS | grep spi1
pin 89 (44e10964): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 100 (44e10990): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 101 (44e10994): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 102 (44e10998): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
pin 103 (44e1099c): 481a0000.spi (GPIO UNCLAIMED) function pinmux_bb_spi1_pins group pinmux_bb_spi1_pins
And the mode is good :
pin 89 (44e10964) 00000012 pinctrl-single
pin 100 (44e10990) 00000013 pinctrl-single
pin 101 (44e10994) 00000033 pinctrl-single
pin 102 (44e10998) 00000013 pinctrl-single
pin 103 (44e1099c) 00000013 pinctrl-single
I successfully use a programm in C which use the first spidev (spidev2.0) with the first chip select, but the there are nothing on pin 42 when I use spidev2.1 (MOSI,MISO and CLK are working though).
Any ideas ?
Thanks in advance

Well I found out the answer myself :
The pin 42 is special since it's connected to two I/O. So in order to use one of the I/O, you have to put the other one as input.
source : Beaglebone black system reference manual http://www.digikey.com/web%20export/supplier%20content/ti_296/mkt/boards/BBB_SRM.pdf?redirected=1 page 71.
But now i have an other issue really strange... I posted it here : Trouble with SPIDEV, device tree and .dtbo name with Beaglebone Black

Related

Cannot send or receive data through UART on PIC24F development board

I am trying to upload a simple UART testing program to a PIC24F Curiosity Board using MPLAB X and validate data transmission using TeraTerm. This evaluation board uses a PIC24FJ128GA204 microcontroller. I have made sure to set the serial port configuration on TeraTerm as it is defined in the program.
For data transmission, I am using a USB to RS-232 UART cable connected to my desktop. I have double checked my cable connections and they are as defined in the program. I am not using the +5 Vcc on the cable and I have connected the cable to ground, but I have tried connected and disconnected ground.
Currently no data will be transmitted, although I have noticed that when I program the board, sometimes TeraTerm will display some random values, which I am not sure if that implies there is a connection capable of data transmission or it is just random noise.
Currently, my UART initialization is as follows:
#include <xc.h>
#define U_ENABLE 0x8008 // enable UART, BREGH=1, 1 stop, 8 data bits, no parity, RTS/CTS flow control
#define U_TX 0x0400 // enable transmission, clear all flags
#define _XTAL_FREQ 8000000 //set to internal oscillator frequency
//** UART2 RS232 asynchronous communication demonstration
void initialize_UART(void) {
U1BRG = 104; // initialize the baud rate generator to 104, an equivalent value of 9524
U1MODE = U_ENABLE; // initialize the UART module
U1STA = U_TX; // enable the receiver
//****CONFIGURING FOR UART****
//MICROCONTROLLER PIN || UART WIRE
//RP0/RB0 = U1RX
//RP1/RB1 = U1CTS (Clear to send)
//RP2/RB2 = U1TX
//RP3/RB3 = UR1RTS ()
// Unlock Registers (per MCU data sheet)
asm volatile ("MOV #OSCCON, w1 \n"
"MOV #0x46, w2 \n"
"MOV #0x57, w3 \n"
"MOV.b w2, [w1] \n"
"MOV.b w3, [w1] \n"
"BCLR OSCCON, #6") ;
// Configure Input Functions (Table 11-3 in Datasheet)
// Assign U1RX To Pin RP0
//RPINR
RPINR18bits.U1RXR = 0;
// Assign U1CTS To Pin RP1
RPINR18bits.U1CTSR = 1;
// Configure Output Functions (Table 11-4 in Datasheet)
// Assign U1TX To Pin RP2
RPOR1bits.RP2R = 3;
// Assign U1RTS To Pin RP3
RPOR1bits.RP3R = 4;
// Lock Registers
asm volatile ("MOV #OSCCON, w1 \n"
"MOV #0x46, w2 \n"
"MOV #0x57, w3 \n"
"MOV.b w2, [w1] \n"
"MOV.b w3, [w1] \n"
"BSET OSCCON, #6") ;
}
My function for sending data through UART:
char UART_send_char(char a)
{
while (PORTBbits.RB1 == 1); //wait for clear to send
while (U1STAbits.UTXBF); //wait while Tx buffer is full
U1TXREG = a;
return a;
}
How I am testing the function in main():
int main(void)
{
TRISA = 0;
// init the UART1 serial port
initialize_UART();
// main loop
while (1)
{
PORTAbits.RA10 = 1; //for debugging purposes
UART_send_char('>');
}
}
This program should continuously send the character ">" to the TeraTerm console, but instead I receive nothing. RA10 is connected to an LED, which does light up so I know the program has entered the main loop, but no data is being sent. I have the configuration bits set to the internal oscillator which operates at 8 MHz and have disabled the PLL. BREGH is set to 1, so I have used the respective formula for the Baud Rate Generator given in the datasheet on page 247 with an Fcy value of 8 MHz/2.
I am new to programming MCUs and have spent some hours trying to fix this to no avail, so any help would be much appreciated.
Here is a complete single file application that runs on the DM240004 PIC24F Curiosity Development Board using a MikroElektronical USB UART click.
/*
* https://github.com/dsoze1138/24FJ128GA204_DM240004
*
* File: main.c
* Author: dan1138
* Target: PIC24FJ128GA204
* Compiler: XC16 v1.60
* IDE: MPLABX v5.45
*
* Created on November 24, 2020, 12:02 PM
*
* PIC24FJ128GA204
* +----------------+ +--------------+ +-----------+ +--------------+
* J4_MOSI <> 1 : RB9/RP9 : LED2 <> 12 : RA10 : J4_SDA <> 23 : RB2/RP2 : X2-32KHZ <> 34 : RA4/SOSCO :
* RGB_G <> 2 : RC6/RP22 : <> 13 : RA7 : J4_SCL <> 24 : RB3/RP3 : LED1 <> 35 : RA9 :
* RGB_B <> 3 : RC7/RP23 : <> 14 : RB14/RP14 : POT <> 25 : RC0/RP16 : J4_CS <> 36 : RC3/RP19 :
* S2 <> 4 : RC8/RP24 : <> 15 : RB15/RP15 : <> 26 : RC1/RP17 : J4_SCK <> 37 : RC4/RP20 :
* S1 <> 5 : RC9/RP25 : GND -> 16 : AVSS : <> 27 : RC2/RP18 : RGB_R <> 38 : RC5/RP21 :
* 3v3 <> 6 : VBAT : 3v3 -> 17 : AVDD : 3v3 -> 28 : VDD : GND -> 39 : VSS :
* 10uF -> 7 : VCAP : ICD_VPP -> 18 : MCLR : GND -> 29 : VSS : 3v3 -> 40 : VDD :
* <> 8 : RB10/RP11/PGD2 : J4_AN <> 19 : RA0/AN0 : <> 30 : RA2/OSCI : J4_RX <> 41 : RB5/RP5/PGD3 :
* <> 9 : RB11/RP11/PGC2 : J4_RST <> 20 : RA1/AN1 : <> 31 : RA3/OSCO : J4_TX <> 42 : RB6/RP6/PGC3 :
* <> 10 : RB12/RP12 : ICD_PGD <> 21 : RB0/RP0/PGD1 : <> 32 : RA8 : <> 43 : RB7/RP7 :
* <> 11 : RB13/RP13 : ICD_PGC <> 22 : RB1/RP1/PGC1 : X2-32KHZ <> 33 : RB4/SOSCI : J4_MISO <> 44 : RB8/RP8 :
* +----------------+ +--------------+ +-----------+ +--------------+
* TQFP-44
*
* Description:
*
* Bare metal initialization of the DM240004 Curiosity Board
*
* Setup the system oscillator for 32MHz using the internal FRC and the 4x PLL.
* Turn on the 32.768KHz secondary oscillator.
* Use UART1 and printf to send a message as 9600 baud.
* Flash LED2 on for 500 milliseconds then off for 500 milliseconds.
*
*/
// CONFIG4
#pragma config DSWDTPS = DSWDTPS1F // Deep Sleep Watchdog Timer Postscale Select bits (1:68719476736 (25.7 Days))
#pragma config DSWDTOSC = LPRC // DSWDT Reference Clock Select (DSWDT uses LPRC as reference clock)
#pragma config DSBOREN = OFF // Deep Sleep BOR Enable bit (DSBOR Disabled)
#pragma config DSWDTEN = OFF // Deep Sleep Watchdog Timer Enable (DSWDT Disabled)
#pragma config DSSWEN = OFF // DSEN Bit Enable (Deep Sleep operation is always disabled)
#pragma config PLLDIV = PLL4X // USB 96 MHz PLL Prescaler Select bits (4x PLL selected)
#pragma config I2C1SEL = DISABLE // Alternate I2C1 enable bit (I2C1 uses SCL1 and SDA1 pins)
#pragma config IOL1WAY = OFF // PPS IOLOCK Set Only Once Enable bit (The IOLOCK bit can be set and cleared using the unlock sequence)
// CONFIG3
#pragma config WPFP = WPFP127 // Write Protection Flash Page Segment Boundary (Page 127 (0x1FC00))
#pragma config SOSCSEL = ON // SOSC Selection bits (SOSC circuit selected)
#pragma config WDTWIN = PS25_0 // Window Mode Watchdog Timer Window Width Select (Watch Dog Timer Window Width is 25 percent)
#pragma config PLLSS = PLL_FRC // PLL Secondary Selection Configuration bit (PLL is fed by the on-chip Fast RC (FRC) oscillator)
#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset Disabled)
#pragma config WPDIS = WPDIS // Segment Write Protection Disable (Disabled)
#pragma config WPCFG = WPCFGDIS // Write Protect Configuration Page Select (Disabled)
#pragma config WPEND = WPENDMEM // Segment Write Protection End Page Select (Write Protect from WPFP to the last page of memory)
// CONFIG2
#pragma config POSCMD = NONE // Primary Oscillator Select (Primary Oscillator Disabled)
#pragma config WDTCLK = LPRC // WDT Clock Source Select bits (WDT uses LPRC)
#pragma config OSCIOFCN = ON // OSCO Pin Configuration (OSCO/CLKO/RA3 functions as port I/O (RA3))
#pragma config FCKSM = CSECMD // Clock Switching and Fail-Safe Clock Monitor Configuration bits (Clock switching is enabled, Fail-Safe Clock Monitor is disabled)
#pragma config FNOSC = FRC // Initial Oscillator Select (Fast RC Oscillator (FRC))
#pragma config ALTCMPI = CxINC_RB // Alternate Comparator Input bit (C1INC is on RB13, C2INC is on RB9 and C3INC is on RA0)
#pragma config WDTCMX = WDTCLK // WDT Clock Source Select bits (WDT clock source is determined by the WDTCLK Configuration bits)
#pragma config IESO = OFF // Internal External Switchover (Disabled)
// CONFIG1
#pragma config WDTPS = PS32768 // Watchdog Timer Postscaler Select (1:32,768)
#pragma config FWPSA = PR128 // WDT Prescaler Ratio Select (1:128)
#pragma config WINDIS = OFF // Windowed WDT Disable (Standard Watchdog Timer)
#pragma config FWDTEN = OFF // Watchdog Timer Enable (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config ICS = PGx1 // Emulator Pin Placement Select bits (Emulator functions are shared with PGEC1/PGED1)
#pragma config LPCFG = OFF // Low power regulator control (Disabled - regardless of RETEN)
#pragma config GWRP = OFF // General Segment Write Protect (Write to program memory allowed)
#pragma config GCP = OFF // General Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = OFF // JTAG Port Enable (Disabled)
/*
* Defines for system oscillator frequency.
* Make sure that the PIC initialization selects this frequency.
*/
#define FSYS (32000000ul)
#define FCY (FSYS/2ul)
/*
* Target specific Special Function Register definitions
*/
#include <xc.h>
/*
* Standard header files
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/*
* Initialize this PIC
*/
void PIC_Init(void)
{
uint16_t ClockSwitchTimeout;
/*
* Disable all interrupt sources
*/
__builtin_disi(0x3FFF); /* disable interrupts for 16383 cycles */
IEC0 = 0;
IEC1 = 0;
IEC2 = 0;
IEC3 = 0;
IEC4 = 0;
IEC5 = 0;
IEC6 = 0;
IEC7 = 0;
__builtin_disi(0x0000); /* enable interrupts */
INTCON1bits.NSTDIS = 1; /* Disable interrupt nesting */
/*
* At Power On Reset the configuration words set the system clock
* to use the FRC oscillator. At this point we need to enable the
* PLL to get the system clock running at 32MHz.
*
* Clock switching on the 24FJ family with the PLL can be a bit tricky.
*
* First we need to check if the configuration words enabled clock
* switching at all, then turn off the PLL, then setup the PLL and
* finally enable it. Sounds simple, I know. Make sure you verify this
* clock setup on the real hardware.
*/
if(!OSCCONbits.CLKLOCK) /* if primary oscillator switching is unlocked */
{
/* Select primary oscillator as FRC */
__builtin_write_OSCCONH(0b000);
/* Request switch primary to new selection */
__builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_OSWEN_POSITION));
/* wait, with timeout, for clock switch to complete */
for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && OSCCONbits.OSWEN;);
CLKDIV = 0x0000; /* set for FRC clock 8MHZ operations */
/* Select primary oscillator as FRCPLL */
__builtin_write_OSCCONH(0b001);
/* Request switch primary to new selection */
__builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_OSWEN_POSITION));
/* ALERT: This may be required only when the 96MHz PLL is used */
CLKDIVbits.PLLEN = 1;
/* wait, with timeout, for clock switch to complete */
for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && OSCCONbits.OSWEN;);
/* wait, with timeout, for the PLL to lock */
for(ClockSwitchTimeout=10000; --ClockSwitchTimeout && !OSCCONbits.LOCK;);
/* at this point the system oscillator should be 32MHz */
}
/* Turn on Secondary Oscillation Amplifier */
__builtin_write_OSCCONL(OSCCON | (1 << _OSCCON_SOSCEN_POSITION));
/* Turn off all analog inputs */
ANSA = 0;
ANSB = 0;
ANSC = 0;
}
/*
* WARNING: Not a portable function.
* Maximum delay 16384 instruction cycles.
* At 16 MIPS this is 1024 microseconds.
*
* Minimum 1MHz instruction cycle clock.
*/
void delay_us(unsigned short delay)
{
if (delay > (uint16_t)(16383.0 / (FCY/1E6)))
{
asm(" repeat #16383\n"
" clrwdt \n"
::);
}
else
{
asm(" repeat %0 \n"
" clrwdt \n"
:: "r" (delay*(uint16_t)(FCY/1000000ul)-1));
}
}
/*
* WARNING: Not a portable function.
* Maximum 16MHz instruction cycle clock.
* Minimum 8Khz instruction cycle clock.
*/
void delay_ms(unsigned long delay)
{
if(delay)
{
asm("1: repeat %0 \n"
" clrwdt \n"
" sub %1,#1 \n"
" subb %d1,#0 \n"
" bra nz,1b \n"
:: "r" (FCY/1000ul-6ul), "C" (delay));
}
}
/*
* Initialize the UART
*/
void UART_Init(void)
{
/**
Set the UART1 module to run at 9600 baud with RB6 as TX out and RB5 as RX in.
*/
TRISBbits.TRISB6 = 0;
LATBbits.LATB6 = 1;
__builtin_write_OSCCONL(OSCCON & ~_OSCCON_IOLOCK_MASK); // unlock PPS
RPINR18bits.U1RXR = 0x0005; //RB5->UART1:U1RX
RPOR3bits.RP6R = 0x0003; //RB6->UART1:U1TX
__builtin_write_OSCCONL(OSCCON | _OSCCON_IOLOCK_MASK); // lock PPS
// STSEL 1; IREN disabled; PDSEL 8N; UARTEN enabled; RTSMD disabled; USIDL disabled; WAKE disabled; ABAUD disabled; LPBACK disabled; BRGH enabled; URXINV disabled; UEN TX_RX;
// Data Bits = 8; Parity = None; Stop Bits = 1;
U1MODE = (0x8008 & ~(1<<15)); // disabling UARTEN bit
// UTXISEL0 TX_ONE_CHAR; UTXINV disabled; URXEN disabled; OERR NO_ERROR_cleared; URXISEL RX_ONE_CHAR; UTXBRK COMPLETED; UTXEN disabled; ADDEN disabled;
U1STA = 0x00;
// BaudRate = 9600; Frequency = 16000000 Hz; U1BRG 416;
U1BRG = 0x1A0;
// ADMADDR 0; ADMMASK 0;
U1ADMD = 0x00;
// T0PD 1 ETU; PTRCL T0; TXRPT Retransmits the error byte once; CONV Direct; SCEN disabled;
U1SCCON = 0x00;
// TXRPTIF disabled; TXRPTIE disabled; WTCIF disabled; WTCIE disabled; PARIE disabled; GTCIF disabled; GTCIE disabled; RXRPTIE disabled; RXRPTIF disabled;
U1SCINT = 0x00;
// GTC 0;
U1GTC = 0x00;
// WTCL 0;
U1WTCL = 0x00;
// WTCH 0;
U1WTCH = 0x00;
U1MODEbits.UARTEN = 1; // enabling UART ON bit
U1STAbits.UTXEN = 1;
}
uint8_t UART1_Read(void)
{
while(!(U1STAbits.URXDA == 1));
if ((U1STAbits.OERR == 1))
{
U1STAbits.OERR = 0;
}
return U1RXREG;
}
void UART1_Write(uint8_t txData)
{
while(U1STAbits.UTXBF == 1);
U1TXREG = txData; // Write the data byte to the USART.
}
bool UART1_IsRxReady(void)
{
return U1STAbits.URXDA;
}
bool UART1_IsTxReady(void)
{
return ((!U1STAbits.UTXBF) && U1STAbits.UTXEN );
}
bool UART1_IsTxDone(void)
{
return U1STAbits.TRMT;
}
int __attribute__((__section__(".libc.write"))) write(int handle, void *buffer, unsigned int len)
{
unsigned int i;
for (i = len; i; --i)
{
UART1_Write(*(char*)buffer++);
}
return(len);
}
/*
* Main Application
*/
int main(void)
{
/*
* Application initialization
*/
PIC_Init();
UART_Init();
/* Set RA10 for output to drive LED2 */
LATAbits.LATA10 = 0;
TRISAbits.TRISA10 = 0;
printf("\r\nPIC24FJ128GA204 built on " __DATE__ " at " __TIME__ " Start\r\n");
/*
* Application process loop
*/
for(;;)
{
LATAbits.LATA10 ^= 1;
delay_ms(500);
}
return 0;
}
I suspect that your problem may be trying to implement hardware handshaking with the RTS/CTS signaling.
Try to get the serial data transmit from the PIC to the PC working at a slow baud rate first.
And another thing is that RB0 and RB1 are used to program (and debug) the PIC24FJ128GA204. The onboard In-Circuit-Serial-Programmer can interfere with using these pins for other functions. In a debug session they cannot be used by the application at all.

Can't access gpio line with gpiod_line_request_output() on Adafruit FT232H

I am using an Adafruit Ft232H breakout to add GPIO ports to my Linux pc. Although I had some success to flash a led with libftdi and bitbang mode, I don't have the same luck with libgpiod because gpiod_line_request_output is failing.
Some gpio information of my system:
sudo gpiodetect
gpiochip0 [ftdi-cbus] (4 lines)
sudo gpioinfo
gpiochip0 - 4 lines:
line 0: unnamed unused input active-high
line 1: unnamed unused input active-high
line 2: unnamed unused input active-high
line 3: unnamed unused input active-high
This is the C program which tries to access the line 0.
#include <stdio.h>
#include <stdlib.h>
#include <gpiod.h>
#define LINE_NUM 0
void gpio_fatal(struct gpiod_chip* chip, const char msg[20]);
int main(int argc, char** argv)
{
struct gpiod_chip* chip;
struct gpiod_line* line;
const char path[] = "/dev/gpiochip0";
chip = gpiod_chip_open(path);
if(!chip)
{
fprintf(stderr, "Error opening path\n");
return EXIT_FAILURE;
}
line = gpiod_chip_get_line(chip, LINE_NUM);
if(!line)
{
fprintf(stderr, "error getting this line\n");
return EXIT_FAILURE;
}
int ret = gpiod_line_request_output(line,
"ftdi-cbus",
1);
if(ret != 0)
gpio_fatal(chip, "Request output failed");
for(;;)
{
gpiod_line_set_value(line, 1);
printf("On\n");
sleep(1);
gpiod_line_set_value(line, 0);
printf("Off\n");
sleep(1);
}
gpiod_line_release(line);
gpiod_chip_close(chip);
return EXIT_SUCCESS;
}
void gpio_fatal(struct gpiod_chip* chip, const char* msg)
{
fprintf(stderr, "%s\n", msg);
gpiod_chip_close(chip);
exit(EXIT_FAILURE);
}
Running the executable with sudo gives me:
sudo g_gpiod/build/g_gpiod
Password:
Request output failed
gpiod.h states for the failing function the following:
/**
* #brief Reserve a single line, set the direction to output.
* #param line GPIO line object.
* #param consumer Name of the consumer.
* #param default_val Initial line value.
* #return 0 if the line was properly reserved, -1 on failure.
*/
int gpiod_line_request_output(struct gpiod_line *line,
const char *consumer, int default_val) GPIOD_API;
The parameters seem to be correct, for what reason could this be failing? Other examples using libftdi or CircuitPython can access the ports and work correctly.
You need to flash the EEPROM to set the function of pin C5, e.g. using the ftdi_eeprom command from libftdi. First, unload the ftdi_sio module and save the original EEPROM:
$ sudo rmmod ftdi_sio
$ sudo ftdi_eeprom --verbose --device i:0x0403:0x6014 ft232h-orig.conf
FTDI eeprom generator v0.17
(c) Intra2net AG and the libftdi developers <opensource#intra2net.com>
FTDI read eeprom: 0
EEPROM size: 256
VID: 0x0403
PID: 0x6014
Release: 0x0900
Bus Powered: 100 mA
Manufacturer: ÿÿÿÿÿÿÿÿ
Product: ÿÿÿÿÿÿ
Serial: ÿÿÿÿÿÿÿÿ
Checksum : ffff
PNP: 1
Channel A has Mode UART
FT1284 Mode Clock is idle LOW, MSB first, No Flow Control
ACBUS has 4 mA drive
ADBUS has 4 mA drive
C0 Function: TRISTATE
C1 Function: TRISTATE
C2 Function: TRISTATE
C3 Function: TRISTATE
C4 Function: TRISTATE
C5 Function: TRISTATE
C6 Function: TRISTATE
C7 Function: TRISTATE
C8 Function: DRIVE_1
C9 Function: DRIVE_0
FTDI close: 0
The file ft232h-orig.conf contains just a single line filename="ft232h-orig.bin".
You can control 4 GPIO pins of the FT232H using the ftdi_sio module:
| line | pin | remarks |
==========================
| 0 | C5 | - |
| 1 | C6 | - |
| 2 | C8 | red led |
| 3 | C9 | green led |
The Adafruit board has the cathodes of two LEDs (red and green) connected to pins C8 and C9. The default EEPROM has C9 set to DRIVE_0 so that the green LED is "on" when the board is powered up.
Here is my config file for ftdi_eeprom:
$ cat ft232h-libgpiod.conf
vendor_id="0x0403"
product_id="0x6014"
manufacturer="Adafruit"
product="FT232H Breakout"
# whatever
serial="20211223"
use_serial=true
max_power=100
self_powered=false
remote_wakeup=false
cha_type=UART
cha_vcp=false
cbush5=IOMODE
cbush6=IOMODE
# red led
cbush8=IOMODE
# green led
cbush9=DRIVE_0 # power-on indicator
#cbush9=IOMODE
$ sudo ftdi_eeprom --verbose --device i:0x0403:0x6014 --flash-eeprom ft232h-libgpiod.conf
Your program now works fine with line 0 on pin C5. As a bonus, you can now control the red LED with the libgpiod commands:
# turn red LED on (low active)
sudo gpioset gpiochip0 2=0

Trouble getting SPI functioning on PIC24

I am trying to configure a PIC24FJ512GA610 to use SPI to interface with an ADC module. As such, I am configuring it in two-wire mode (only SCK and SDI, CS controlled by ports). Below is the relevant code I am using to configure the SPI. A header file contains most definitions:
// SPI3 is used to read from 22-bit ADC tied to RTDs
// SPI3CON1L
#define SPI3EN 0<<15 // SPI Enable Pin
// unimplemented
#define SPI3SIDL 0<<13 // Stop when CPU is in idle mode
#define SPI3DSSDO 1<<12 // Disable SDO (no data sent to ADC module)
#define SPI3MODE1 0<<11 // Data mode: (0,0) transmits 8-bits
#define SPI3MODE0 0<<10 //
#define SPI3SMP 1<<9 // Sampling phase: samples at the end of output data time
#define SPI3CKE 0<<8 // Transmits on transition from idle to active
#define SPI3SSEN 0<<7 // only used in slave mode
#define SPI3CKP 0<<6 // clock idle state is low, active state is high
#define SPI3MSTEN 1<<5 // Master mode enabled
#define SPI3DISSDI 0<<4 // Disable SDI (no data received the board))
#define SPI3DISSCK 0<<3
#define SPI3MCLKEN 1<<2
#define SPI3SPIFE 0<<1
#define SPI3ENHBUF 0<<0
#define SPI3CON1L_MASK (SPI3EN | SPI3SIDL | SPI3DSSDO | SPI3MODE1 | SPI3MODE0 | SPI3SMP |\
SPI3CKE | SPI3SSEN | SPI3CKP | SPI3MSTEN | SPI3DISSDI | SPI3DISSCK | SPI3MCLKEN |\
SPI3SPIFE | SPI3ENHBUF )
// SPI3CON1H
#define AUDEN3 0<<15 // Audio codec enable
#define SPI3SGNEXT 0<<14 // Sign Extend Enable
#define IGNROV3 0<<13 // Ignore Receive Overflow
#define IGNTUR3 0<<12 // Ignore Transmit Underrun
#define AUDMONO3 0<<11 // Audio data format
#define URDTEN3 0<<10 // Transmit underrun data enable
#define AUDMOD31 0<<9 // Audio protocol mode select
#define AUDMOD30 0<<8 //
#define FRMEN3 1<<7 // Framed SPI support
#define FRMSYNC3 0<<6 // Frame sync pulse direction control
#define FRMPOL3 0<<5 // Frame sync/slave select polarity bit
#define MSSEN3 0<<4 // Master mode slave select enable
#define FRMSYPW3 0<<3 // Frame sync pulse width bit
#define FRMCNT32 0<<2 // Frame sync pulse counter bits
#define FRMCNT31 0<<1 //
#define FRMCNT30 0<<0 //
#define SPI3CON1H_MASK (AUDEN3 | SPI3SGNEXT | IGNROV3 | IGNTUR3 | AUDMONO3 | URDTEN3 | AUDMOD31 |\
AUDMOD30 | FRMEN3 | FRMSYNC3 | FRMPOL3 | MSSEN3 | FRMSYPW3 | FRMCNT32 |\
FRMCNT31 | FRMCNT30 )
The function that configures the SPI is found elsewhere:
void SPI3Init(void)
// SPI 3 is the thermocouple interface chip or
// the external adc interface for the cryostat
// **************************************
{
#if PROCESSOR == __PIC24FJ512GA610__
// Used for SPI communication to read RTDs through ADC
IEC3bits.SPI3RXIE = 0; // disable all SPI3 interrupts
IEC5bits.SPI3TXIE = 0;
IEC5bits.SPI3IE = 0;
SPI3BUFL = 0; // clear buffer
SPI3BUFH = 0;
OSCCONbits.IOLOCK = 0;
RPINR28bits.SDI3R = 30; // assign SPI3 SDI to pin 52 (RP30)
// RPINR28bits.SCK3R = 15; // assign SPI3 SCK to pin 53 (RP15)
RPOR7bits.RP15R = 24; // Set SCK pin to SPI3 SCK OUT (function 24)
RPOR8bits.RP16R = 23; // Map SDO to N/C pin 51 (function 23)
OSCCONbits.IOLOCK = 1;
SPI3CON1Lbits.SPIEN = 0; // disable the port
SPI3IMSKH = 0; // disable all interrupts
SPI3CON1L = 0; // disable SPI
SPI3CON1H = 0; // turn off AUDEN & FRMEN
SPI3BRGL = 832; // 3=16mhz / (2* (3+1)) = 2mhz, 7=16/2(7+1) = 1mhz, 832 -> 9600 )
SPI3CON1L = SPI3CON1L_MASK; // Write config masks
SPI3CON1H = SPI3CON1H_MASK;
SPI3CON2L = 7; // 8 bit data
SPI3STATLbits.SPIROV = 0; // clear any overflow status
SPI3CON1Lbits.SPIEN = 1; // enable the port
SPI3BUFL = 0;
ADC_CS_HIGH;
ADC_CS_LOW;
ADC_CS_HIGH;
#endif
return;
}
Actually reading the ADC calls this function three times (one for each 8 bits of resolution)
unsigned char Read_SPI3()
{
unsigned char ioByte = 0;
if(SPI3STATLbits.SPIROV)
SPI3STATLbits.SPIROV = 0; // clear overflow
SPI3BUFL = ioByte; // CLK out data on falling edge
while(!SPI3STATLbits.SPIRBF)
;
ioByte = SPI3BUFL; // CLK in data on rising edge
return ioByte;
}
I have been going through my code for the last day or two and, after combing the internet, cannot figure out what I am doing wrong. Putting a scope on the SCK line indicates that the serial clock is not running. I have confirmed that the config bits are being successfully written. Can anybody tell me what might be wrong?
A few thoughts:
Your setting for DISSDI is enabling SDI (comment says disable)
TRIS register settings are not given, but the pin for SDI must be 1, and the pin for SCLK must be set to 0
by setting MCKLEN, your clock source is REFO - assume it is configured correctly? (e.g. ROEN=1)
With this:
RPOR7bits.RP15R = 24;
you are mapping your SCLK pin to RF8. But you had to switch this pin to an output with.
TRISFbits.TRISF8 = 0;
And you had to switch this pin to digital with
ANSELFbits.ANSELF8 = 0;
Same thing for the SDO pin.
And as #Dan already mentiones, you need a unlock/lock sequence for the PPS. Have aloo at page 163 in the datasheet
The statement you use to unlock the pin selector:
OSCCONbits.IOLOCK = 0;
Is not what Microchip requires.
Because all of the writable bits in the OSCCON register are "protected" a built in compiler extension command must be used to change them.
The command to unlock the PPS looks like this:
__builtin_write_OSCCONL(OSCCON & _OSCCON_IOLOCK_MASK);
The command to lock the PPS looks like this:
__builtin_write_OSCCONL(OSCCON | _OSCCON_IOLOCK_MASK);
Depending on how you have set the configuration words the PPS may be configured so it cannot be unlocked, and once locked it takes a power-on-reset for the PPS to become unlocked.

On STM32F7 DMA triggered by APB1 timers fails

I have STM32F7 Disco board with STM32F723IEK MCU. Trying to trigger a DMA request from a timer causes a DMA error, but only for timers from the APB1 group (TIM2 to TIM7 and others), that are connected to DMA1. Doing the same with TIM1 and TIM8, which are connected to DMA2, works fine. The error manifests itself as the TEIFx flag being set in the appropriate DMA LISR or HISR register and DMA immediately disabled after the first transaction. The NDTR register is decremented by one.
According to the datasheet, the TEIF error may be triggered by a "bus error". I understand this as e.g. trying to access a peripheral that is not accessible from the DMA bus. However, the same setup works well using DMA2 and TIM1/TIM8, without changing the DMA address. So the problem seems to be related to DMA request and not the data transaction itself. Given that there are lot of timer channels defined for DMA1, this should certainly work.
I have tried to vary DMA settings but this made no difference. The relevant portion of the test program is below. The full version https://github.com/ak-hard/stm32-dma-tim/blob/master/main.c is only slightly larger and have no dependencies except CMSIS and STM32 Device headers.
I wonder if someone can comment on or reproduce this problem.
const struct
{
TIM_TypeDef *tim;
DMA_TypeDef *dma;
DMA_Stream_TypeDef *stream;
unsigned channel;
} CFG = {
// uncomment the needed combination below, only TIM1 and TIM8 work
// TIM1, DMA2, DMA2_Stream5, 6
TIM8, DMA2, DMA2_Stream1, 7
// TIM2, DMA1, DMA1_Stream1, 3
// TIM2, DMA1, DMA1_Stream7, 3
// TIM3, DMA1, DMA1_Stream2, 5
// TIM4, DMA1, DMA1_Stream6, 2
// TIM5, DMA1, DMA1_Stream0, 6
// TIM5, DMA1, DMA1_Stream6, 6
// TIM6, DMA1, DMA1_Stream1, 7
// TIM7, DMA1, DMA1_Stream2, 1
// TIM7, DMA1, DMA1_Stream4, 1
};
enum
{
DMA_SxCR_DIR_P2M = 0,
DMA_SxCR_PSIZE_WORD = DMA_SxCR_PSIZE_1,
DMA_SxCR_MSIZE_WORD = DMA_SxCR_MSIZE_1,
};
#define DMA_SxCR_CHSEL_NUM(ch) ((ch) << DMA_SxCR_CHSEL_Pos)
uint32_t buf;
void start(void)
{
SysTick->LOAD = 0xffffffu;
SysTick->VAL = 0;
SysTick->CTRL = 5;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM8EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN | RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM4EN | RCC_APB1ENR_TIM5EN
| RCC_APB1ENR_TIM6EN | RCC_APB1ENR_TIM7EN;
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN | RCC_AHB1ENR_DMA2EN;
LED_PORT->MODER |= 1 << (2 * LED_PIN);
LED_PORT->OSPEEDR |= 3 << (2 * LED_PIN); // fastest speed
CFG.tim->CR1 |= TIM_CR1_ARPE;
CFG.tim->ARR = 16;
CFG.tim->PSC = 1000;
CFG.tim->EGR = TIM_EGR_UG; // Generate Update Event to copy ARR to its shadow
CFG.tim->DIER |= TIM_DIER_UDE;
CFG.stream->CR |= DMA_SxCR_CHSEL_NUM(CFG.channel) | DMA_SxCR_DIR_P2M | DMA_SxCR_PSIZE_WORD | DMA_SxCR_MSIZE_WORD;
CFG.stream->NDTR = 16;
CFG.stream->PAR = (uint32_t) &GPIOA->IDR;
CFG.stream->M0AR = (uint32_t) &buf;
CFG.stream->CR |= DMA_SxCR_EN;
CFG.tim->CR1 |= TIM_CR1_CEN;
// wait until DMA state changes
while (CFG.dma->LISR == 0 && CFG.dma->HISR == 0)
delay_ms(1);
// check for any TEIFx bits
int error = (CFG.dma->LISR | CFG.dma->HISR) & 0x02080208;
while (1)
{
LED_PORT->ODR ^= 1 << LED_PIN;
delay_ms(error ? 100 : 500);
}
}
There used to an answer here but it got deleted for some reason. Thanks to its author though.
Looking at the bus matrix, it becomes clear that the peripheral bus of the DMA1 is only connected to APB1. It is actually not a part of the matrix at all. This probably means that DMA1 can only handle transfers from/to APB1 peripherals. Since GPIO is an AHB peripheral, it is not accessible from DMA1. This should also apply to other APB2 (e.g. SPI1) and AHB peripherals (e.g. OTGFS). Normally, it does not make sense to access AHB or APB2 peripherals from DMA1 because their requests are not routed to DMA1. However, it may be needed for convoluted cases like GPIO by a timer.
I personally think this point could be made more obvious in the documentation.

CAN communication between LPC 2292 and LPC1758 boards "Start of Frame " error

I am trying to setup CAN communication between a couple of LPC device nodes. My setup includes a couple of CAN nodes writing on to the CAN bus. For example LPC 2292 CAN controller can write on to the CAN bus and the LPC1758 can receive the data. This works perfectly fine. Now LPC1758 has 2 CAN controllers and I have setup one for receiving data and the other for transmitting data on the bus as a response. I also setup interrupt handlers for LPC 1758 CAN 1 transmit & receive and CAN 2 transmit & receive. ( I dont have code for LPC 2292. its not under my control)
My problem is at the LPC1758 side. Here the CAN 1 receiver is able to get the data from the other CAN nodes as I can see the interrupt vector handler being called. The problem is when the the LPC 1758 CAN 2 tranmistter writes to the bus . It gets a bus error . More specificially "Start of Frame " error . ( I use a Ulink2 debugger). Now reading the CAN specs I know the start frame of the CAN message should start with a low ( dominant) bit CAN specs ; See page 3
How do I go about fixing this error ? Its not a configurable register that I can set the first bit to 0 or 1. I run the default LPC 1758 CAN code that comes with KEIL C:\Keil_v5\ARM\Boards\Keil\MCB1700\CAN I think the code is fine because when I run the code in simulation mode of KEIL I can see the CAN commnication work well.
Is this "Start of Frame" a by product of some other configurations that I am missing ?
Update Code :
I run the default LPC 1758 CAN code that comes with KEIL C:\Keil_v5\ARM\Boards\Keil\MCB1700\CAN I think the code is fine because when I run the code in simulation mode of KEIL I can see the CAN communication work well. Also I did not make any changes to the code except the baudrate.
CAN setup :
/*----------------------------------------------------------------------------
setup CAN interface. CAN controller (1..2)
*----------------------------------------------------------------------------*/
void CAN_setup (uint32_t ctrl) {
LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
if (ctrl == 1) {
LPC_SC->PCONP |= (1 << 13); /* Enable power to CAN1 block */
LPC_PINCON->PINSEL0 |= (1 << 0); /* Pin P0.0 used as RD1 (CAN1) */
LPC_PINCON->PINSEL0 |= (1 << 2); /* Pin P0.1 used as TD1 (CAN1) */
NVIC_EnableIRQ(CAN_IRQn); /* Enable CAN interrupt */
} else {
LPC_SC->PCONP |= (1 << 14); /* Enable power to CAN2 block */
LPC_PINCON->PINSEL4 |= (1 << 14); /* Pin P2.7 used as RD2 (CAN2) */
LPC_PINCON->PINSEL4 |= (1 << 16); /* Pin P2.8 used as TD2 (CAN2) */
NVIC_EnableIRQ(CAN_IRQn); /* Enable CAN interrupt */
}
LPC_CANAF->AFMR = 2; /* By default filter is not used */
pCAN->MOD = 1; /* Enter reset mode */
pCAN->IER = 0; /* Disable all interrupts */
pCAN->GSR = 0; /* Clear status register */
CAN_cfgBaudrate(ctrl, /*250000*/ 100000); /* Set bit timing */
pCAN->IER = 0x0003; /* Enable Tx and Rx interrupt */
//pCAN->IER = 0x7FF;
}
Here is my code to transmit and receive:
/*----------------------------------------------------------------------------
wite a message to CAN peripheral and transmit it. CAN controller (1..2)
*----------------------------------------------------------------------------*/
void CAN_wrMsg (uint32_t ctrl, CAN_msg *msg) {
LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
uint32_t CANData;
CANData = (((uint32_t) msg->len) << 16) & 0x000F0000 |
(msg->format == EXTENDED_FORMAT ) * 0x80000000 |
(msg->type == REMOTE_FRAME) * 0x40000000;
if (pCAN->SR & (1<<2)) { /* Transmit buffer 1 free */
pCAN->TFI1 = CANData; /* Write frame informations */
pCAN->TID1 = msg->id; /* Write CAN message identifier */
pCAN->TDA1 = *(uint32_t *) &msg->data[0]; /* Write first 4 data bytes */
pCAN->TDB1 = *(uint32_t *) &msg->data[4]; /* Write second 4 data bytes */
//pCAN->CMR = 0x31; /* Select Tx1 for Self Tx/Rx */
pCAN->CMR = 0x21; /* Start transmission without loop-back */ -- Here is when "Start of Frame " error happens
}
}
Receive code is fine but still posting
/*----------------------------------------------------------------------------
read a message from CAN peripheral and release it. CAN controller (1..2)
*----------------------------------------------------------------------------*/
void CAN_rdMsg (uint32_t ctrl, CAN_msg *msg) {
LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
uint32_t CANData;
/* Read frame informations */
CANData = pCAN->RFS;
msg->format = (CANData & 0x80000000) == 0x80000000;
msg->type = (CANData & 0x40000000) == 0x40000000;
msg->len = ((uint8_t)(CANData >> 16)) & 0x0F;
msg->id = pCAN->RID; /* Read CAN message identifier */
if (msg->type == DATA_FRAME) { /* Read the data if received message was DATA FRAME */
*(uint32_t *) &msg->data[0] = pCAN->RDA;
*(uint32_t *) &msg->data[4] = pCAN->RDB;
}
}
Baudrate Calculation:
/*----------------------------------------------------------------------------
configure the requested baudrate. CAN controller (1..2)
*----------------------------------------------------------------------------*/
static void CAN_cfgBaudrate (uint32_t ctrl, uint32_t baudrate) {
LPC_CAN_TypeDef *pCAN = (ctrl == 1) ? LPC_CAN1 : LPC_CAN2;
uint32_t result = 0;
uint32_t nominal_time;
/* Determine which nominal time to use for PCLK */
if (((PCLK / 1000000) % 6) == 0) {
nominal_time = 12; /* PCLK based on 72MHz CCLK */
} else {
nominal_time = 10; /* PCLK based on 100MHz CCLK */
}
/* Prepare value appropriate for bit time register */
result = (PCLK / nominal_time) / baudrate - 1;
result &= 0x000003FF;
result |= CAN_BIT_TIME[nominal_time];
pCAN->BTR = result; /* Set bit timing */
}
I am finally able to get rid of the "Start of Frame " error that had being bogging me down. I had a discussion with some of our other CAN bus code authors and he suggested i use the same CAN controller for sending and receiving. In short this:
** Does not work** :
LPC 2292 : CAN 1 Rx & CAN 2 Tx
LPC 1750 : CAN 1 Rx & CAN 2 TX
** WORKS** :
LPC 2292 : CAN 1 Rx & CAN 1 Tx
LPC 1750 : CAN 1 Rx & CAN 1 TX
Being a newbie i may have made this mistake. But the default code provided by KEIL shows using alternate CAN controllers for sending and transmitting. I hope this helps someone .

Resources