Skip to content

Commit 0f71e02

Browse files
committed
[ftdi] Add gpio backend
1 parent 8061b9d commit 0f71e02

3 files changed

Lines changed: 184 additions & 0 deletions

File tree

lib/ftdi/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ add_library(ftdipp)
77
target_sources(ftdipp
88
PRIVATE
99
spi_host.cc
10+
gpio.cc
1011
PUBLIC
1112
FILE_SET HEADERS
1213
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}
1314
FILES
1415
ftdi.hh
1516
spi_host.hh
17+
gpio.hh
1618
log.hh
1719
)
1820

lib/ftdi/gpio.cc

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright lowRISC contributors.
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#include "gpio.hh"
6+
#include "libft4222.h"
7+
#include "libmpsse_spi.h"
8+
#include "ftd2xx.h"
9+
#include <iostream>
10+
#include <format>
11+
#include <print>
12+
13+
namespace ftdi {
14+
15+
void Gpio::close() {
16+
if (mpsse) {
17+
SPI_CloseChannel(handle);
18+
Cleanup_libMPSSE();
19+
} else {
20+
FT4222_UnInitialize(handle);
21+
FT_Close(handle);
22+
}
23+
}
24+
25+
embeddedpp::Result<bool> Gpio::get_pin(uint8_t pin) {
26+
uint8_t mask = static_cast<uint8_t>(1 << pin);
27+
if (mpsse) {
28+
if (pin > 7) {
29+
std::cerr << std::format("gpio pin must be 0-7\n");
30+
return embeddedpp::Code::InvalidArgument;
31+
}
32+
uint8_t value = 0;
33+
FT_STATUS status = FT_ReadGPIO(handle, &value);
34+
return (value & mask) == mask;
35+
}
36+
37+
if (pin > 3) {
38+
std::cerr << std::format("gpio pin must be 0-3\n");
39+
return embeddedpp::Code::InvalidArgument;
40+
}
41+
42+
GPIO_Port port = static_cast<GPIO_Port>(pin);
43+
BOOL enable;
44+
FT4222_STATUS status = FT4222_GPIO_Read(handle, port, &enable);
45+
if (FT4222_OK != status) {
46+
std::cerr << std::format("FT4222_GPIO_Read: {}\n", status);
47+
return embeddedpp::Code::Generic;
48+
}
49+
return enable > 0;
50+
}
51+
52+
embeddedpp::Status Gpio::set_pin(uint8_t pin, bool en) {
53+
if (mpsse) {
54+
if (pin > 7) {
55+
std::cerr << std::format("gpio pin must be 0-7\n");
56+
return embeddedpp::Code::InvalidArgument;
57+
}
58+
uint8_t value = 0;
59+
FT_STATUS status;
60+
status = FT_ReadGPIO(handle, &value);
61+
if (en) {
62+
value |= static_cast<uint8_t>(1 << pin);
63+
} else {
64+
value &= static_cast<uint8_t>(~(1 << pin));
65+
}
66+
status = FT_WriteGPIO(handle, 0xff, value);
67+
if (FT_OK != status) {
68+
std::cerr << std::format("FT_WriteGPIO: {}\n", status);
69+
return embeddedpp::Code::Generic;
70+
}
71+
return true;
72+
}
73+
74+
if (pin > 3) {
75+
std::cerr << std::format("gpio pin must be 0-3\n");
76+
return embeddedpp::Code::InvalidArgument;
77+
}
78+
79+
GPIO_Port port = static_cast<GPIO_Port>(pin);
80+
FT4222_STATUS status = FT4222_GPIO_Write(handle, port, en ? TRUE : FALSE);
81+
if (FT4222_OK != status) {
82+
std::cerr << std::format("FT4222_GPIO_Write: {}\n", status);
83+
return embeddedpp::Code::Generic;
84+
}
85+
return embeddedpp::Code::Ok;
86+
}
87+
88+
static std::optional<Gpio> new_ft4222_gpio(DeviceInfo& device) {
89+
FT_HANDLE handle;
90+
FT_STATUS res = FT_OpenEx((PVOID)(uintptr_t)device.loc_id, FT_OPEN_BY_LOCATION, &handle);
91+
if (res != FT_OK) {
92+
std::cerr << std::format("Gpio Open:{}\n", res);
93+
return std::nullopt;
94+
}
95+
96+
// Initialize all four GPIO pins as outputs.
97+
GPIO_Dir dir[4] = {GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT};
98+
FT4222_STATUS status = FT4222_GPIO_Init(handle, dir);
99+
if (FT4222_OK != status) {
100+
std::cerr << std::format("FT4222_GPIO_Init:{}\n", status);
101+
FT_Close(handle);
102+
return std::nullopt;
103+
}
104+
105+
return std::optional<Gpio>{handle};
106+
}
107+
108+
static std::optional<Gpio> new_ft2232_gpio(DeviceInfo& device) {
109+
FT_HANDLE handle;
110+
FT_STATUS res;
111+
const uint32_t channel = 0;
112+
Init_libMPSSE();
113+
114+
std::println("Opening {}, channel {}", device.serial_number, channel);
115+
res = SPI_OpenChannel(channel, &handle);
116+
if (res != FT_OK) {
117+
std::cerr << std::format("Gpio Open:{}\n", res);
118+
Cleanup_libMPSSE();
119+
return std::nullopt;
120+
}
121+
122+
ChannelConfig config = {.ClockRate = 1000000, // 1MHz
123+
.LatencyTimer = 2,
124+
.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3 |
125+
SPI_CONFIG_OPTION_CS_ACTIVELOW};
126+
res = SPI_InitChannel(handle, &config);
127+
if (res != FT_OK) {
128+
std::cerr << std::format("Spi InitChannel: {}\n", res);
129+
return std::nullopt;
130+
}
131+
132+
return std::optional<Gpio>{Gpio(handle, true)};
133+
}
134+
135+
std::optional<Gpio> Gpio::from_device_info(DeviceInfo& device) {
136+
switch (device.type) {
137+
case DeviceType::Ftdi_2232h:
138+
return new_ft2232_gpio(device);
139+
case DeviceType::Ftdi_4222h_0:
140+
case DeviceType::Ftdi_4222h_1_2:
141+
case DeviceType::Ftdi_4222h_3:
142+
return new_ft4222_gpio(device);
143+
default:
144+
break;
145+
}
146+
std::cerr << std::format("Gpio: device not supported {}\n", device);
147+
return std::nullopt;
148+
}
149+
150+
}; // namespace ftdi

lib/ftdi/gpio.hh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright lowRISC contributors.
2+
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#pragma once
6+
7+
#include <cstdint>
8+
#include <optional>
9+
#include "libft4222.h"
10+
#include "ftdi.hh"
11+
#include "embeddedpp/helpers.hh"
12+
13+
namespace ftdi {
14+
15+
class Gpio {
16+
FT_HANDLE handle;
17+
bool mpsse = false;
18+
19+
public:
20+
explicit Gpio(FT_HANDLE handle) noexcept : handle(handle) {}
21+
Gpio(FT_HANDLE handle, bool mpsse) noexcept : handle(handle), mpsse(mpsse) {}
22+
~Gpio() = default;
23+
24+
void close();
25+
26+
embeddedpp::Status set_pin(uint8_t pin, bool value);
27+
embeddedpp::Result<bool> get_pin(uint8_t pin);
28+
29+
static std::optional<Gpio> from_device_info(DeviceInfo& device);
30+
};
31+
32+
} // namespace ftdi

0 commit comments

Comments
 (0)