Skip to content

Instantly share code, notes, and snippets.

@trabucayre
Last active July 15, 2022 06:58
Show Gist options
  • Select an option

  • Save trabucayre/2f31c0b46bd4d95af1287d4e6eecd3e6 to your computer and use it in GitHub Desktop.

Select an option

Save trabucayre/2f31c0b46bd4d95af1287d4e6eecd3e6 to your computer and use it in GitHub Desktop.
libgpiod wrapper for JTAG
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <gpiod.h>
#include <cstring>
#include <stdexcept>
/*!
* \brief LibGPIOD driver
*/
class MyGPIOD {
public:
/*!
* \brief constructor: open a device and configure JTAG pins
* \param[in] devname: gpiochip peripheral (/dev/gpiochipX)
* \param[in] tms_off: tms pin ID
* \param[in] tck_off: tck pin ID
* \param[in] tdo_off: tdo pin ID
* \param[in] tdi_off: tdi pin ID
*/
MyGPIOD(const char *devname, uint32_t tms_off, uint32_t tck_off,
uint32_t tdo_off, uint32_t tdi_off):_devname(devname),
_tms(tms_off), _tck(tck_off), _tdo(tdo_off), _tdi(tdi_off),
_chip(NULL), _lines(GPIOD_LINE_BULK_INITIALIZER), _tdo_line(NULL)
{
if (open_device() < 0)
throw std::runtime_error("gpio periphral access failed");
}
/*!
* \brief destructor: release pins and peripheral
*/
~MyGPIOD() {
close_device();
}
/*!
* \brief open a device and configure pins
* \return 0 on success, -1 otherwise
*/
int open_device();
/*!
* \brief release pins and close peripheral
*/
void close_device();
/*!
* \brief update tms, tdi pins with tck low then high, read tdo if asked and
* tck low again when end
* \param[in] tms: tms pin state (0/1)
* \param[in] tdi: tdi pin state (0/1)
* \param[in] tdo: sample tdo line when not NULL
* \param[in] end: set tck low before return
* \return 0 when success, -1 otherwise
*/
int set_pins(int tms, int tdi, uint8_t *tdo, bool end);
private:
/*!
* Update tms tdi and tck pins state
* \param[in] tck: tck pin state (0/1)
* \param[in] tms: tms pin state (0/1)
* \param[in] tdi: tdi pin state (0/1)
* \return 0 when success, -1 otherwise
*/
int update_pins(int tck, int tms, int tdi);
const char *_devname; /*!< /dev/gpiochipx name */
uint32_t _tms, _tck, _tdo, _tdi; /*!< JTAG pins ID */
gpiod_chip *_chip; /*!< libGPIOD peripheral */
struct gpiod_line_bulk _lines; /*!< TDI, TMS, TCK lines */
struct gpiod_line *_tdo_line; /*!< TDO only */
};
int MyGPIOD::open_device()
{
/* try to open device by full path (/dev/gpiochipXXX) */
_chip = gpiod_chip_open(_devname);
if (!_chip) {
printf("gpiod chip failed\n");
return -1;
}
/* TMS, TDI and TCK configuration */
uint32_t offs[3]= {_tck, _tms, _tdi};
int vals[3]= {0, 1, 0};
/* get lines */
int ret = gpiod_chip_get_lines(_chip, offs, 3, &_lines);
if (ret == -1) {
printf("Unable to get gpio lines\n");
return ret;
}
/* request lines -> all as output */
ret = gpiod_line_request_bulk_output(&_lines, "openFPGALoader", vals);
if (ret < 0) {
printf("Error requesting gpio lines\n");
}
/* default state */
ret = gpiod_line_set_value_bulk(&_lines, vals);
if (ret < 0) {
printf("Error set default value\n");
}
/* TDO line (input) */
_tdo_line = gpiod_chip_get_line(_chip, _tdo);
if (!_tdo_line) {
printf("Unable to get gpio line %d\n", _tdo);
return -1;
}
if (gpiod_line_request_input(_tdo_line, "openFPGALoader") < 0) {
printf("Error requesting gpio line %d\n", _tdo);
return -1;
}
return 0;
}
void MyGPIOD::close_device()
{
if (_lines.lines)
gpiod_line_release_bulk(&_lines);
if (_tdo_line)
gpiod_line_release(_tdo_line);
if (_chip)
gpiod_chip_close(_chip);
}
int MyGPIOD::update_pins(int tck, int tms, int tdi)
{
int vals[3] = {tck, tms, tdi};
if (gpiod_line_set_value_bulk(&_lines, vals) < 0) {
printf("Unable to update gpio lines\n");
return -1;
}
return 0;
}
int MyGPIOD::set_pins(int tms, int tdi, uint8_t *tdo, bool end)
{
/* first update all lines with clk set to low (before read) */
if (update_pins(0, tms, tdi) == -1)
return -1;
/* keep tms/tdi and set clk set to high (sampling edge) */
if (update_pins(1, tms, tdi) == -1)
return -1;
/* read? after clk rise: TDO must be stable */
if (tdo) {
int tmp;
if ((tmp = gpiod_line_get_value(_tdo_line)) < 0)
return -1;
*tdo = static_cast<uint8_t>(tmp);
}
/* security: if it's the last bit from a buffer set clk low */
if (end) {
if (update_pins(0, tms, tdi) == -1)
return -1;
}
return 0;
}
#define DEV_GPIO "gpiochip0\0"
/* PIN 32 */
#define TCK 12
/* PIN 34 */
/* GND */
/* PIN 36 */
#define TDI 16
/* PIN 38 */
#define TDO 20
/* PIN 40 */
#define TMS 21
int main()
{
int ret = EXIT_SUCCESS;
MyGPIOD mygpiod(DEV_GPIO, TMS, TCK, TDO, TDI);
printf("Press Key");
getchar();
for (uint8_t c = 0; c < 16; c++) {
if (mygpiod.set_pins(((c >> 1) & 0x01), (c & 0x01), NULL, c == 15) == -1) {
ret = EXIT_FAILURE;
break;
}
}
char c = 0x55;
for (uint8_t i = 0; i < 8; i++) {
if (mygpiod.set_pins(i == 7, ((c >> i) & 0x01), NULL, i == 7) == -1) {
ret = EXIT_FAILURE;
break;
}
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment