master de4a019076c7 cached
19 files
34.7 KB
10.4k tokens
10 symbols
1 requests
Download .txt
Repository: Nicolai-Electronics/rp2040-i2c-interface
Branch: master
Commit: de4a019076c7
Files: 19
Total size: 34.7 KB

Directory structure:
gitextract_0gfx8glm/

├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── LICENSE_MIT
├── Makefile
├── README.md
├── example/
│   ├── 400kHz.sh
│   ├── README.md
│   ├── disable_kde_compositor.sh
│   ├── run.sh
│   └── ssd1306.py
├── kernel_i2c_flags.h
├── main.c
├── pico_sdk_import.cmake
├── tools/
│   └── 99-pico.rules
├── tusb_config.h
├── usb_descriptors.c
├── usb_descriptors.h
└── version.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .clang-format
================================================
---
Language:        Cpp
# BasedOnStyle:  Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveMacros: true
AlignConsecutiveAssignments: true
AlignConsecutiveBitFields: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Left
AlignOperands:   Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
  - __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
  AfterCaseLabel:  false
  AfterClass:      false
  AfterControlStatement: Never
  AfterEnum:       false
  AfterFunction:   false
  AfterNamespace:  false
  AfterObjCDeclaration: false
  AfterStruct:     false
  AfterUnion:      false
  AfterExternBlock: false
  BeforeCatch:     false
  BeforeElse:      false
  BeforeLambdaBody: false
  BeforeWhile:     false
  IndentBraces:    false
  SplitEmptyFunction: true
  SplitEmptyRecord: true
  SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit:     160
CommentPragmas:  '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: true
DisableFormat:   false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
  - foreach
  - Q_FOREACH
  - BOOST_FOREACH
IfMacros:
  - KJ_IF_MAYBE
IncludeBlocks:   Regroup
IncludeCategories:
  - Regex:           '^<ext/.*\.h>'
    Priority:        2
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '^<.*\.h>'
    Priority:        1
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '^<.*'
    Priority:        2
    SortPriority:    0
    CaseSensitive:   false
  - Regex:           '.*'
    Priority:        3
    SortPriority:    0
    CaseSensitive:   false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires:  false
IndentWidth:     4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd:   ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth:   -1
RawStringFormats:
  - Language:        Cpp
    Delimiters:
      - cc
      - CC
      - cpp
      - Cpp
      - CPP
      - 'c++'
      - 'C++'
    CanonicalDelimiter: ''
    BasedOnStyle:    google
  - Language:        TextProto
    Delimiters:
      - pb
      - PB
      - proto
      - PROTO
    EnclosingFunctions:
      - EqualsProto
      - EquivToProto
      - PARSE_PARTIAL_TEXT_PROTO
      - PARSE_TEST_PROTO
      - PARSE_TEXT_PROTO
      - ParseTextOrDie
      - ParseTextProtoOrDie
      - ParseTestProto
      - ParsePartialTestProto
    CanonicalDelimiter: pb
    BasedOnStyle:    google
ReferenceAlignment: Pointer
ReflowComments:  true
ShortNamespaceLines: 1
SortIncludes:    CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles:  Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
  Minimum:         1
  Maximum:         -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard:        Auto
StatementAttributeLikeMacros:
  - Q_EMIT
StatementMacros:
  - Q_UNUSED
  - QT_REQUIRE_VERSION
TabWidth:        8
UseCRLF:         false
UseTab:          Never
WhitespaceSensitiveMacros:
  - STRINGIZE
  - PP_STRINGIZE
  - BOOST_PP_STRINGIZE
  - NS_SWIFT_NAME
  - CF_SWIFT_NAME
...



================================================
FILE: .gitignore
================================================
build
release
generated


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.12)

message("Build type: \"${CMAKE_BUILD_TYPE}\"")

# Project name
set(NAME i2c_adapter)

# Board type
set(PICO_BOARD none)

# Fixes that allow some MCH2022 badges with a slowly starting oscillator to boot properly
add_compile_definitions(PICO_BOOT_STAGE2_CHOOSE_GENERIC_03H=1 PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64)

# SDK
include($ENV{PICO_SDK_PATH}/pico_sdk_init.cmake)

project(${NAME} C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0")
    message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()

pico_sdk_init()

# Firmware
add_executable(${NAME}
    main.c
    usb_descriptors.c
)

target_include_directories(${NAME} PUBLIC
        ${CMAKE_CURRENT_LIST_DIR})

target_link_libraries(${NAME}
    pico_stdlib
    pico_unique_id
    hardware_watchdog
    hardware_flash
    hardware_uart
    hardware_pio
    hardware_pwm
    hardware_adc
    hardware_i2c
    tinyusb_device
    tinyusb_board
    cmsis_core
)

pico_add_extra_outputs(${NAME})


================================================
FILE: LICENSE_MIT
================================================
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: Makefile
================================================
# Copyright (c) 2022 Nicolai Electronics
# SPDX-License-Identifier: MIT

INSTALL_PREFIX := $PWD
BUILD_DIR := build
GENERATED_DIR := generated

.PHONY: all firmware flash clean install_rules $(BUILD_DIR) format

all: build flash
	@echo "All tasks completed"

build:
	mkdir -p $(BUILD_DIR)
	mkdir -p $(GENERATED_DIR)
	cd $(BUILD_DIR); cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_BUILD_TYPE=Release ..
	$(MAKE) -C $(BUILD_DIR) --no-print-directory all

debug:
	mkdir -p $(BUILD_DIR)
	mkdir -p $(GENERATED_DIR)
	cd $(BUILD_DIR); cmake -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_BUILD_TYPE=Debug ..
	$(MAKE) -C $(BUILD_DIR) --no-print-directory all

flash:
	picotool load $(BUILD_DIR)/i2c_adapter.bin
	picotool reboot

clean:
	rm -rf $(BUILD_DIR)
	rm -rf $(GENERATED_DIR)

install_rules:
	cp tools/99-pico.rules /etc/udev/rules.d/
	@echo "reload rules with:"
	@echo "\tudevadm control --reload-rules"
	@echo "\tudevadm trigger"

format:
	find . -iname '*.h' -o -iname '*.c' -o -iname '*.cpp' | grep -v '$(BUILD_DIR)' | xargs clang-format -i


================================================
FILE: README.md
================================================
# I2C interface

This RP2040 firmware implements the USB protocol expected by the I2C-Tiny-USB kernel driver, allowing the use of a Raspberry Pi Pico as USB to I2C adapter.

The original I2C-Tiny-USB project can be found at https://github.com/harbaum/I2C-Tiny-USB, this firmware is a complete re-implementation of the firmware for use with the RP2040.

More testing is needed to verify that the firmware works correctly, this project currently has proof of concept status.

## Pinout

* SDA (i2c data): GPIO 2
* SCL (i2c clock): GPIO 3


================================================
FILE: example/400kHz.sh
================================================
#!/usr/bin/env bash

# The kernel module accepts a delay in us as a parameter
# the default value of 10us converts to a clock speed of 1000000 / 10 = 100 kHz
# the RP2040 supports 400kHz too, setting a delay of 2 us results in
# 1000000 / 2 = 500 kHz but the firmware automatically limits the speed to 400 kHz
#
# This script disables the kernel module and then enables it again in 400kHz mode.

rmmod i2c-tiny-usb
modprobe i2c-tiny-usb delay=2


================================================
FILE: example/README.md
================================================
# Example

A simple demonstration showing how to control an OLED display (SSD1306) via I2C.

## Contents

* 400khz.sh - Run as root, this script switches I2C speed from 100kHz to 400kHz
* disable_kde_compositor.sh - Run as your user, this script disables the compositor function of the KDE desktop, which causes problems when capturing the screen with FFMPEG
* run.sh - Run as root, this script starts FFMPEG to record the screen, piping the raw video data to the Python script, run this script to start the demonstration
* ssd1306.py - A very simple and ugly SSD1306 OLED driver in Python using the smbus python library


![photo](photo.jpg)

[![Demonstration video](http://img.youtube.com/vi/PMtY5OU9V3Q/0.jpg)](http://www.youtube.com/watch?v=PMtY5OU9V3Q "Demonstration video")


## Linux tools

You can easily list and access the I2C busses of your computer, including the bus exposed by this project by loading the i2c-dev kernel module. Please do watch out: some devices on internal I2C busses  inside your computer may malfunction or cause damage when probing busses or performing read/write operations using these tools.

You can find the device number of the RP2040 I2C adapter by running the dmesg command right after plugging in the device. You are looking for the following line of information:

```
$ sudo dmesg
...
i2c i2c-1: connected i2c-tiny-usb device
```

In this example the I2C bus number assigned to the RP2040 I2C adapter is 1. This means the device file is `/dev/i2c-1` and the sysfs interface is `/sys/bus/i2c/devices/i2c-1`.

To enable access to the I2C busses of the computer via the device file the i2c-dev kernel module needs to be loaded.

```
sudo modprobe i2c-dev
```

Busses can then be probed using i2cdetect:

```
sudo i2cdetect -y 1
```

In which the number (1) is the bus number. To scan all I2C addresses add the `-a` flag before the bus number.

To read a value from a register in an I2C device the i2cget command can be used:

```
sudo i2cget -y 1 0x28 0x00
```

In which 1 is the bus number, 0x28 is the I2C device address and 0x00 is the register number.

To write a value to a register in an I2C device the i2cset command can be used:

```
sudo i2cset -y 1 0x28 0x00 0x42
```

In wich 1 is the bus number, 0x28 is the I2C device address, 0x00 is the register number and 0x42 is the value written to the register.


================================================
FILE: example/disable_kde_compositor.sh
================================================
#!/usr/bin/env bash

# This script temporarily disables the compositor function of the KDE plasma desktop as it causes glitches when recording the screen with ffmpeg

qdbus org.kde.KWin /Compositor suspend


================================================
FILE: example/run.sh
================================================
#!/usr/bin/env bash
ffmpeg -framerate 16 -f x11grab -video_size 1920x1080 -i :0+0,0 -f image2pipe -vf scale=128x64 -pix_fmt monob -vcodec rawvideo - | python -u ssd1306.py


================================================
FILE: example/ssd1306.py
================================================
import smbus, sys, time
bus = smbus.SMBus(1)

def init():
    bus.write_byte_data(0x3c, 0x00, 0xae)
    bus.write_byte_data(0x3c, 0x00, 0xd5)
    bus.write_byte_data(0x3c, 0x00, 0x80)
    bus.write_byte_data(0x3c, 0x00, 0xa8)
    bus.write_byte_data(0x3c, 0x00, 0x3f)
    bus.write_byte_data(0x3c, 0x00, 0xd3)
    bus.write_byte_data(0x3c, 0x00, 0x00)
    bus.write_byte_data(0x3c, 0x00, 0x40)
    bus.write_byte_data(0x3c, 0x00, 0x20)
    bus.write_byte_data(0x3c, 0x00, 0x00)
    bus.write_byte_data(0x3c, 0x00, 0xa1)
    bus.write_byte_data(0x3c, 0x00, 0xc8)
    bus.write_byte_data(0x3c, 0x00, 0xda)
    bus.write_byte_data(0x3c, 0x00, 0x12)
    bus.write_byte_data(0x3c, 0x00, 0x81)
    bus.write_byte_data(0x3c, 0x00, 0xcf)
    bus.write_byte_data(0x3c, 0x00, 0xd9)
    bus.write_byte_data(0x3c, 0x00, 0xf1)
    bus.write_byte_data(0x3c, 0x00, 0xdb)
    bus.write_byte_data(0x3c, 0x00, 0x30)
    bus.write_byte_data(0x3c, 0x00, 0x8d)
    bus.write_byte_data(0x3c, 0x00, 0x14)
    bus.write_byte_data(0x3c, 0x00, 0x2e)
    bus.write_byte_data(0x3c, 0x00, 0xa4)
    bus.write_byte_data(0x3c, 0x00, 0xa6)
    bus.write_byte_data(0x3c, 0x00, 0xaf)

def position(x0 = 0, x1 = 127, y0 = 0, y1 = 7):
    bus.write_byte_data(0x3c, 0x00, 0x21)
    bus.write_byte_data(0x3c, 0x00, x0)
    bus.write_byte_data(0x3c, 0x00, x1)
    bus.write_byte_data(0x3c, 0x00, 0x22)
    bus.write_byte_data(0x3c, 0x00, y0)
    bus.write_byte_data(0x3c, 0x00, y1)

init()
position()

def convert(data_in):
    data_out = [0x00] * 128 * 8
    for x in range(128):
        for y in range(64):
            in_addr = x // 8 + (y * 128//8)
            in_bit = 7 - x % 8
            out_addr = x + ((y // 8)*128)
            out_bit = y % 8
            if data_in[in_addr] & 1 << in_bit:
                data_out[out_addr] |= 1 << out_bit
    return data_out

for x in range(64):
    bus.write_i2c_block_data(0x3c, 0x40, [0x00] * 16)

while True:
    data_in = list(sys.stdin.buffer.read(128*64//8))
    data_out = convert(data_in)
    for position in range(128*8//32):
        out = data_out[position*32:(position*32)+32]
        bus.write_i2c_block_data(0x3c, 0x40, out)


================================================
FILE: kernel_i2c_flags.h
================================================
#pragma once

/* linux kernel flags */
#define I2C_M_TEN          0x10 /* we have a ten bit chip address */
#define I2C_M_RD           0x01
#define I2C_M_NOSTART      0x4000
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK   0x1000
#define I2C_M_NO_RD_ACK    0x0800

/* To determine what functionality is present */
#define I2C_FUNC_I2C                        0x00000001
#define I2C_FUNC_10BIT_ADDR                 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING          0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
#define I2C_FUNC_SMBUS_HWPEC_CALC           0x00000008 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_READ_WORD_DATA_PEC   0x00000800 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA_PEC  0x00001000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_PROC_CALL_PEC        0x00002000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC  0x00004000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL      0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK                0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE            0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE           0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA       0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA      0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA       0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA      0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL            0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA      0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA     0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK       0x04000000 /* I2C-like block xfer  */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK      0x08000000 /* w/ 1-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2     0x10000000 /* I2C-like block xfer  */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2    0x20000000 /* w/ 2-byte reg. addr. */
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA_PEC  0x40000000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC 0x80000000 /* SMBus 2.0 */

#define I2C_FUNC_SMBUS_BYTE       I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE
#define I2C_FUNC_SMBUS_BYTE_DATA  I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA
#define I2C_FUNC_SMBUS_WORD_DATA  I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA
#define I2C_FUNC_SMBUS_BLOCK_DATA I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA
#define I2C_FUNC_SMBUS_I2C_BLOCK  I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK

#define I2C_FUNC_SMBUS_EMUL                                                                                                       \
    I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | \
        I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA_PEC | I2C_FUNC_SMBUS_I2C_BLOCK


================================================
FILE: main.c
================================================
/**
 * Copyright (c) 2022 Nicolai Electronics
 *
 * SPDX-License-Identifier: MIT
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "bsp/board.h"
#include "hardware/adc.h"
#include "hardware/i2c.h"
#include "hardware/irq.h"
#include "hardware/pwm.h"
#include "hardware/structs/watchdog.h"
#include "hardware/uart.h"
#include "hardware/watchdog.h"
#include "kernel_i2c_flags.h"
#include "pico/bootrom.h"
#include "pico/stdlib.h"
#include "tusb.h"
#include "usb_descriptors.h"

#define I2C_INST i2c1
#define I2C_SDA  2
#define I2C_SCL  3

int main(void) {
    board_init();
    tusb_init();

    gpio_init(I2C_SDA);
    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
    gpio_pull_up(I2C_SDA);

    gpio_init(I2C_SCL);
    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
    gpio_pull_up(I2C_SCL);

    i2c_init(I2C_INST, 100000);

    while (1) {
        tud_task();
    }

    return 0;
}

// Invoked when device is mounted
void tud_mount_cb(void) {}

// Invoked when device is unmounted
void tud_umount_cb(void) {}

// Invoked when usb bus is suspended
void tud_suspend_cb(bool remote_wakeup_en) {}

// Invoked when usb bus is resumed
void tud_resume_cb(void) {}

/* commands from USB, must e.g. match command ids in kernel driver */
#define CMD_ECHO       0
#define CMD_GET_FUNC   1
#define CMD_SET_DELAY  2
#define CMD_GET_STATUS 3
#define CMD_I2C_IO     4
#define CMD_I2C_BEGIN  1  // flag fo I2C_IO
#define CMD_I2C_END    2  // flag fo I2C_IO

const unsigned long i2c_func = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;

#define STATUS_IDLE        0
#define STATUS_ADDRESS_ACK 1
#define STATUS_ADDRESS_NAK 2

static uint8_t i2c_state = STATUS_IDLE;

uint8_t i2c_data[1024] = {0};

/*uint8_t buffer[256] = {0};
void debug_print(const char* buffer) {
    tud_cdc_n_write(0, buffer, strlen(buffer));
    tud_cdc_n_write_flush(0);
}*/

bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
    if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR) {
        switch (request->bRequest) {
            case CMD_ECHO:
                if (stage != CONTROL_STAGE_SETUP) return true;
                return tud_control_xfer(rhport, request, (void*) &request->wValue, sizeof(request->wValue));
            case CMD_GET_FUNC:
                if (stage != CONTROL_STAGE_SETUP) return true;
                return tud_control_xfer(rhport, request, (void*) &i2c_func, sizeof(i2c_func));
                break;
            case CMD_SET_DELAY:
                if (stage != CONTROL_STAGE_SETUP) return true;
                if (request->wValue == 0) {
                    i2c_set_baudrate(I2C_INST, 100000);  // Use default: 100kHz
                } else {
                    int baudrate = 1000000 / request->wValue;
                    if (baudrate > 400000) baudrate = 400000;  // Limit to 400kHz
                    i2c_set_baudrate(I2C_INST, baudrate);
                }
                return tud_control_status(rhport, request);
            case CMD_GET_STATUS:
                if (stage != CONTROL_STAGE_SETUP) return true;
                return tud_control_xfer(rhport, request, (void*) &i2c_state, sizeof(i2c_state));
            case CMD_I2C_IO:
            case CMD_I2C_IO + CMD_I2C_BEGIN:
            case CMD_I2C_IO + CMD_I2C_END:
            case CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END:
                {
                    if (stage != CONTROL_STAGE_SETUP && stage != CONTROL_STAGE_DATA) return true;
                    bool nostop = !(request->bRequest & CMD_I2C_END);

                    //sprintf(buffer, "%s i2c %s at 0x%02x, len = %d, nostop = %d\r\n", (stage != CONTROL_STAGE_SETUP) ? "[D]" : "[S]", (request->wValue & I2C_M_RD)?"rd":"wr", request->wIndex, request->wLength, nostop);
                    //debug_print(buffer);

                    if (request->wLength > sizeof(i2c_data)) {
                        return false;  // Prevent buffer overflow in case host sends us an impossible request
                    }

                    if (stage == CONTROL_STAGE_SETUP) {  // Before transfering data
                        if (request->wValue & I2C_M_RD) {
                            // Reading from I2C device
                            int res = i2c_read_blocking(I2C_INST, request->wIndex, i2c_data, request->wLength, nostop);
                            if (res == PICO_ERROR_GENERIC) {
                                i2c_state = STATUS_ADDRESS_NAK;
                            } else {
                                i2c_state = STATUS_ADDRESS_ACK;
                            }
                        } else if (request->wLength == 0) {  // Writing with length of 0, this is used for bus scanning, do dummy read
                            uint8_t dummy = 0x00;
                            int     res   = i2c_read_blocking(I2C_INST, request->wIndex, (void*) &dummy, 1, nostop);
                            if (res == PICO_ERROR_GENERIC) {
                                i2c_state = STATUS_ADDRESS_NAK;
                            } else {
                                i2c_state = STATUS_ADDRESS_ACK;
                            }
                        }
                        tud_control_xfer(rhport, request, (void*) i2c_data, request->wLength);
                    }

                    if (stage == CONTROL_STAGE_DATA) {        // After transfering data
                        if (!(request->wValue & I2C_M_RD)) {  // I2C write operation
                            int res = i2c_write_blocking(I2C_INST, request->wIndex, i2c_data, request->wLength, nostop);
                            if (res == PICO_ERROR_GENERIC) {
                                i2c_state = STATUS_ADDRESS_NAK;
                            } else {
                                i2c_state = STATUS_ADDRESS_ACK;
                            }
                        }
                    }

                    return true;
                }
            default:
                if (stage != CONTROL_STAGE_SETUP) return true;
                break;
        }
    } else {
        if (stage != CONTROL_STAGE_SETUP) return true;
    }

    return false;  // stall unknown request
}

bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const* request) {
    (void) rhport;
    (void) request;
    return true;
}


================================================
FILE: pico_sdk_import.cmake
================================================
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake

# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()

if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
    set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
    message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()

if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
    set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
    message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()

if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
    set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
    message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()

set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")

if (NOT PICO_SDK_PATH)
    if (PICO_SDK_FETCH_FROM_GIT)
        include(FetchContent)
        set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
        if (PICO_SDK_FETCH_FROM_GIT_PATH)
            get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
        endif ()
        FetchContent_Declare(
                pico_sdk
                GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
                GIT_TAG master
        )
        if (NOT pico_sdk)
            message("Downloading Raspberry Pi Pico SDK")
            FetchContent_Populate(pico_sdk)
            set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
        endif ()
        set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
    else ()
        message(FATAL_ERROR
                "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
                )
    endif ()
endif ()

get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()

set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
    message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()

set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)

include(${PICO_SDK_INIT_CMAKE_FILE})


================================================
FILE: tools/99-pico.rules
================================================
# /etc/udev/rules.d/99-pico.rules

SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0005", SYMLINK+="pico"


================================================
FILE: tusb_config.h
================================================
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2019 Ha Thach (tinyusb.org)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_

#ifdef __cplusplus
extern "C" {
#endif

//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------

// defined by board.mk
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif

// RHPort number used for device can be defined by board.mk, default to port 0
#ifndef BOARD_DEVICE_RHPORT_NUM
#define BOARD_DEVICE_RHPORT_NUM 0
#endif

// RHPort max operational speed can defined by board.mk
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
#ifndef BOARD_DEVICE_RHPORT_SPEED
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || CFG_TUSB_MCU == OPT_MCU_NUC505 || \
     CFG_TUSB_MCU == OPT_MCU_CXD56 || CFG_TUSB_MCU == OPT_MCU_SAMX7X)
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
#else
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#endif
#endif

// Device mode with rhport and speed defined by board.mk
#if BOARD_DEVICE_RHPORT_NUM == 0
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#elif BOARD_DEVICE_RHPORT_NUM == 1
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
#else
#error "Incorrect RHPort configuration"
#endif

#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif

// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG           0

/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
 * Tinyusb use follows macros to declare transferring memory so that they can be put
 * into those specific section.
 * e.g
 * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
 * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
 */
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif

#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
#endif

//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------

#ifndef CFG_TUD_ENDPOINT0_SIZE
#define CFG_TUD_ENDPOINT0_SIZE 64
#endif

//------------- CLASS -------------//
#define CFG_TUD_HID    0
#define CFG_TUD_CDC    0
#define CFG_TUD_MSC    0
#define CFG_TUD_MIDI   0
#define CFG_TUD_VENDOR 1

#define CFG_TUD_CDC_RX_BUFSIZE 256
#define CFG_TUD_CDC_TX_BUFSIZE 256

#define CFG_TUD_VENDOR_EPSIZE     32
#define CFG_TUD_VENDOR_EP_BUFSIZE 512
#define CFG_TUD_VENDOR_RX_BUFSIZE 512
#define CFG_TUD_VENDOR_TX_BUFSIZE 512

// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_EP_BUFSIZE 16

// MSC Buffer size of Device Mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512

#ifdef __cplusplus
}
#endif

#endif /* _TUSB_CONFIG_H_ */


================================================
FILE: usb_descriptors.c
================================================
/**
 * Copyright (c) 2022 Nicolai Electronics
 * Copyright (c) 2019 Ha Thach (tinyusb.org)
 *
 * SPDX-License-Identifier: MIT
 */

#include "usb_descriptors.h"

#include "bsp/board.h"
#include "pico/unique_id.h"
#include "tusb.h"

// String descriptors

char const* string_desc_arr[] = {
    (const char[]){0x09, 0x04},  // 0: is supported language is English (0x0409)
    "Nicolai Electronics",       // 1: Manufacturer
    "I2C adapter",               // 2: Product
    "I2C interface",             // 3: I2C (vendor) interface
    //"Debug"                      // 4: Debug (cdc) interface
};

enum {
    STRING_DESC = 0,
    STRING_DESC_MANUFACTURER,
    STRING_DESC_PRODUCT,
    STRING_DESC_VENDOR_0,
    // STRING_DESC_CDC_0,
    STRING_DESC_SERIAL  // (Not in the string description array)
};

static uint16_t _desc_str[32];

uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
    (void) langid;
    uint8_t chr_count;
    if (index == STRING_DESC) {
        memcpy(&_desc_str[1], string_desc_arr[0], 2);
        chr_count = 1;
    } else if (index == STRING_DESC_SERIAL) {
        pico_unique_board_id_t id;
        pico_get_unique_board_id(&id);
        const uint8_t* str = id.id;
        chr_count          = 16;
        for (uint8_t len = 0; len < chr_count; ++len) {
            uint8_t c = str[len >> 1];
            c         = ((c >> (((len & 1) ^ 1) << 2)) & 0x0F) + '0';
            if (c > '9') {
                c += 7;
            }
            _desc_str[1 + len] = c;
        }
    } else {
        // Convert ASCII string into UTF-16
        if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0]))) {
            return NULL;
        }
        const char* str = string_desc_arr[index];
        // Cap at max char
        chr_count = strlen(str);
        if (chr_count > 31) chr_count = 31;
        for (uint8_t i = 0; i < chr_count; i++) {
            _desc_str[1 + i] = str[i];
        }
    }

    // first byte is length (including header), second byte is string type
    _desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);

    return _desc_str;
}

// Device descriptors

tusb_desc_device_t const desc_device = {
    .bLength            = sizeof(tusb_desc_device_t),
    .bDescriptorType    = TUSB_DESC_DEVICE,
    .bcdUSB             = 0x0210,  // Supported USB standard (2.1)
    .bDeviceClass       = TUSB_CLASS_MISC,
    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,    // Endpoint 0 packet size
    .idVendor           = 0x1c40,                    // Vendor identifier
    .idProduct          = 0x0534,                    // Product identifier
    .bcdDevice          = 0x0100,                    // Protocol version
    .iManufacturer      = STRING_DESC_MANUFACTURER,  // Index of manufacturer name string
    .iProduct           = STRING_DESC_PRODUCT,       // Index of product name string
    .iSerialNumber      = STRING_DESC_SERIAL,        // Index of serial number string
    .bNumConfigurations = 0x01                       // Number of configurations supported
};

uint8_t const* tud_descriptor_device_cb(void) { return (uint8_t const*) &desc_device; }

// Configuration Descriptor

#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN + CFG_TUD_VENDOR * TUD_VENDOR_DESC_LEN)

#define EPNUM_VENDOR_0_OUT 0x01  // Endpoint 1
#define EPNUM_VENDOR_0_IN  0x81

/*#define EPNUM_CDC_0_NOTIF 0x82  // Endpoint 2: CDC serial port for ESP32 console, control
#define EPNUM_CDC_0_OUT   0x03  // Endpoint 3: CDC serial port for ESP32 console, data
#define EPNUM_CDC_0_IN    0x83*/

uint8_t const desc_fs_configuration[] = {
    // Config number, interface count, string index, total length, attribute, power in mA
    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),

    // WebUSB: Interface number, string index, EP Out & IN address, EP size
    TUD_VENDOR_DESCRIPTOR(ITF_NUM_VENDOR_0, STRING_DESC_VENDOR_0, EPNUM_VENDOR_0_OUT, EPNUM_VENDOR_0_IN, 32),

    // CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
    // TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, STRING_DESC_CDC_0, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
};

uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
    (void) index;
    return desc_fs_configuration;
}


================================================
FILE: usb_descriptors.h
================================================
#pragma once

#include <stdint.h>

// enum { ITF_NUM_VENDOR_0, ITF_NUM_CDC_0, ITF_NUM_CDC_0_DATA, ITF_NUM_TOTAL };
enum { ITF_NUM_VENDOR_0, ITF_NUM_TOTAL };


================================================
FILE: version.h
================================================
#pragma once

#define FW_VERSION 0x01
Download .txt
gitextract_0gfx8glm/

├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── LICENSE_MIT
├── Makefile
├── README.md
├── example/
│   ├── 400kHz.sh
│   ├── README.md
│   ├── disable_kde_compositor.sh
│   ├── run.sh
│   └── ssd1306.py
├── kernel_i2c_flags.h
├── main.c
├── pico_sdk_import.cmake
├── tools/
│   └── 99-pico.rules
├── tusb_config.h
├── usb_descriptors.c
├── usb_descriptors.h
└── version.h
Download .txt
SYMBOL INDEX (10 symbols across 2 files)

FILE: example/ssd1306.py
  function init (line 4) | def init():
  function position (line 32) | def position(x0 = 0, x1 = 127, y0 = 0, y1 = 7):
  function convert (line 43) | def convert(data_in):

FILE: main.c
  function main (line 29) | int main(void) {
  function tud_mount_cb (line 51) | void tud_mount_cb(void) {}
  function tud_umount_cb (line 54) | void tud_umount_cb(void) {}
  function tud_suspend_cb (line 57) | void tud_suspend_cb(bool remote_wakeup_en) {}
  function tud_resume_cb (line 60) | void tud_resume_cb(void) {}
  function tud_vendor_control_xfer_cb (line 87) | bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_cont...
  function tud_vendor_control_complete_cb (line 170) | bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request...
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (38K chars).
[
  {
    "path": ".clang-format",
    "chars": 5674,
    "preview": "---\nLanguage:        Cpp\n# BasedOnStyle:  Google\nAccessModifierOffset: -1\nAlignAfterOpenBracket: Align\nAlignArrayOfStruc"
  },
  {
    "path": ".gitignore",
    "chars": 24,
    "preview": "build\nrelease\ngenerated\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 1117,
    "preview": "cmake_minimum_required(VERSION 3.12)\n\nmessage(\"Build type: \\\"${CMAKE_BUILD_TYPE}\\\"\")\n\n# Project name\nset(NAME i2c_adapte"
  },
  {
    "path": "LICENSE_MIT",
    "chars": 1023,
    "preview": "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentati"
  },
  {
    "path": "Makefile",
    "chars": 1049,
    "preview": "# Copyright (c) 2022 Nicolai Electronics\n# SPDX-License-Identifier: MIT\n\nINSTALL_PREFIX := $PWD\nBUILD_DIR := build\nGENER"
  },
  {
    "path": "README.md",
    "chars": 536,
    "preview": "# I2C interface\n\nThis RP2040 firmware implements the USB protocol expected by the I2C-Tiny-USB kernel driver, allowing t"
  },
  {
    "path": "example/400kHz.sh",
    "chars": 445,
    "preview": "#!/usr/bin/env bash\n\n# The kernel module accepts a delay in us as a parameter\n# the default value of 10us converts to a "
  },
  {
    "path": "example/README.md",
    "chars": 2355,
    "preview": "# Example\n\nA simple demonstration showing how to control an OLED display (SSD1306) via I2C.\n\n## Contents\n\n* 400khz.sh - "
  },
  {
    "path": "example/disable_kde_compositor.sh",
    "chars": 206,
    "preview": "#!/usr/bin/env bash\n\n# This script temporarily disables the compositor function of the KDE plasma desktop as it causes g"
  },
  {
    "path": "example/run.sh",
    "chars": 172,
    "preview": "#!/usr/bin/env bash\nffmpeg -framerate 16 -f x11grab -video_size 1920x1080 -i :0+0,0 -f image2pipe -vf scale=128x64 -pix_"
  },
  {
    "path": "example/ssd1306.py",
    "chars": 2147,
    "preview": "import smbus, sys, time\nbus = smbus.SMBus(1)\n\ndef init():\n    bus.write_byte_data(0x3c, 0x00, 0xae)\n    bus.write_byte_d"
  },
  {
    "path": "kernel_i2c_flags.h",
    "chars": 2823,
    "preview": "#pragma once\n\n/* linux kernel flags */\n#define I2C_M_TEN          0x10 /* we have a ten bit chip address */\n#define I2C_"
  },
  {
    "path": "main.c",
    "chars": 6316,
    "preview": "/**\n * Copyright (c) 2022 Nicolai Electronics\n *\n * SPDX-License-Identifier: MIT\n */\n\n#include <stdio.h>\n#include <stdli"
  },
  {
    "path": "pico_sdk_import.cmake",
    "chars": 2763,
    "preview": "# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake\n\n# This can be dropped into an external project to he"
  },
  {
    "path": "tools/99-pico.rules",
    "chars": 201,
    "preview": "# /etc/udev/rules.d/99-pico.rules\n\nSUBSYSTEM==\"usb\", ATTRS{idVendor}==\"2e8a\", ATTRS{idProduct}==\"0003\", MODE=\"0666\"\nSUBS"
  },
  {
    "path": "tusb_config.h",
    "chars": 4052,
    "preview": "/*\n * The MIT License (MIT)\n *\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * Permission is hereby granted, free of "
  },
  {
    "path": "usb_descriptors.c",
    "chars": 4428,
    "preview": "/**\n * Copyright (c) 2022 Nicolai Electronics\n * Copyright (c) 2019 Ha Thach (tinyusb.org)\n *\n * SPDX-License-Identifier"
  },
  {
    "path": "usb_descriptors.h",
    "chars": 157,
    "preview": "#pragma once\n\n#include <stdint.h>\n\n// enum { ITF_NUM_VENDOR_0, ITF_NUM_CDC_0, ITF_NUM_CDC_0_DATA, ITF_NUM_TOTAL };\nenum "
  },
  {
    "path": "version.h",
    "chars": 38,
    "preview": "#pragma once\n\n#define FW_VERSION 0x01\n"
  }
]

About this extraction

This page contains the full source code of the Nicolai-Electronics/rp2040-i2c-interface GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (34.7 KB), approximately 10.4k tokens, and a symbol index with 10 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!