How to build your very own keyboard firmware

User avatar
redesigndavid

21 Apr 2015, 15:34

I can confirm it was the bootmagic build option that cost my firmware to fail on my keyboard. does enabling that require some special sauce? like certain keys should be available or something?

User avatar
vivalarevolución
formerly prdlm2009

23 Apr 2015, 01:34

Hey guys, I could use a little help with creating a new keymap for my keyboard. I'm using Terminal in Mac OS, by the way. My keyboard already has the firmware built and loaded and I have been typing on the current keymap for months. I followed the guide and created a new keymap, but I receive an error message when I try compile the hex file. Anybody know what is going on? The error message says this:

keymap_common.c:21:46: error: unknown type name 'key_t'
uint8_t keymap_key_to_keycode(uint8_t layer, key_t key)
^
make: *** [obj_gh60_lufa/keymap_common.o] Error 1


Also, here is the keymap that I am attempting to load onto the keyboard:

Code: Select all

#include "keymap_common.h"

const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    
    /* 0: qwerty */
            KEYMAP(
                  ESC,  1,    2,    3,    4,    5,    6,    7,    8,    9,    0,    MINS, EQL,  BSLS, GRV,  DEL, \
                  TAB,        Q,    W,    E,    R,    T,    Y,    U,    I,    O,    P,    LBRC, RBRC, BSPC, PGUP, \
                  LCTL,       A,    S,    D,    F,    G,    H,    J,    K,    L,    SCLN, QUOT,       ENT,  PGDN, \
                  LSFT,       Z,    X,    C,    V,    B,    N,    M,    COMM, DOT,  SLSH, RSFT, UP,   FN1, \
                  CAPS, LALT,     LGUI,                    FN0,                    RGUI, RALT, LEFT, DOWN, RGHT),
    /* 1: FN1 */
        KEYMAP (
                  TRNS,F1,  F2,  F3,  F4, F5,  F6,  F7,  F8,  F9,  F10, F11, F12, TRNS,TRNS, INS, \
                  TRNS,     HOME ,UP,  END,PGUP,TRNS,PGUP,HOME,UP,END,PSCR,SLCK,  PAUS,DEL, HOME, \
                  TRNS,     LEFT,DOWN,RGHT,PGDN,TRNS,PGDN,LEFT,DOWN,RIGHT,TRNS,TRNS,  TRNS,END, \
                  TRNS,          TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,TRNS,PGUP,TRNS, \
                  TRNS, TRNS,     TRNS,               TRNS,               TRNS,TRNS,HOME,PGDN,END),
   /* 2: alt layout */
        KEYMAP (
                  ESC,  1,    2,    3,    4,    5,    6,    7,    8,    9,    0,    MINS, EQL,  BSLS, GRV,  DEL, \
                  TAB,        Q,    P,    I,    Y,    B,    V,    M,   U,    L,    SCLN,    LBRC, RBRC, BSPC, PGUP, \
                  LCTL,       A,    N,    E,    S,    F,    D,    T,    H,    O,    R, QUOT,       ENT,  PGDN, \
                  LSFT,          COMM,    DOT,    C,    G,    SLSH,    J,    W,    K, Z,  X, RSFT, UP,   FN1, \
                  CAPS, LALT,     LGUI,                    FN0,                    RGUI, RALT, LEFT, DOWN, RGHT),
};
const uint16_t PROGMEM fn_actions[] = {
    /* Poker Layout */
    [0] = ACTION_LAYER_TAP_KEY(1, KC_SPC),  // to Fn overlay
    [1] = ACTION_LAYER_TOGGLE(2),
    
};

User avatar
Ray

23 Apr 2015, 18:18

get the new code from github, looks like this has been fixed. It is keypos_t instead of key_t

max517

26 Apr 2015, 06:18

hasu wrote: TMK also has Cortex-M support now, in fact it works on Infinity(Freescale Kinetis) and I could port PS2-USB converter to NXP LPC11U35. But I didn't try Teensy3.1 yet. TMK uses CMSIS and HAL layer of mbed.org to support the MCU, this means, you are on the shoulders of the giants. Theoretically you can use any MCU mbed.org supports freely like chips from NXP, Freescale, STMicro, Nordic, Renesas. Also you will be able to make use of mbed libraries, code samples and tools.

Meanwhile HaaTa's Kiibohd uses its own concise libraries and PJRC USB stack. You'll be able to grasp its outline and hack it yourself.
What would be involved in getting TMK loaded on the Teensy-LC which uses the MKL26Z64VFT4 processor with the Cortex-M0+ core?

The sticking points I'm wondering about so far are as follows:

1) In matt3o's tutorial, you use winavr (at least on Windows). What compiler would you use to generate the .hex file for the Teensy-LC? What modifications do you need to make? Only change the 'MCU =...' line in the makefile?

2)The teensy-lc documentation seems based on using Arduino/Teensyduino. This uses a simplified pin naming and accessing scheme, 0-26. I'm new to Arduino but it seems to limit you to accessing only 1 pin at a time, vs accessing entire Ports and masking out the bits you want. I can't find any documentation for the Teensy-LC showing how to access it's pins through C. I think you would need the mapping from Pin[0-26] -> Port[A-F] Pin ## (assuming the ARM still uses pins such as these).

Anybody have any thoughts about the above points, or other issues I'm likely missing?
Thanks!

User avatar
hasu

26 Apr 2015, 11:28

See Infinity project(keyboard/infinity/) to know how TMK works with mbed SDK.

First, you will need to change HAL implementation for the MCU, for example startup codes and linker script.
In mbed.org KL26Z is not supported yet while KL25Z is, I don't know how different the two controllers are but probably they are very similar and most of code can be shared.
See keyboard/infinity/mbed-infinity/ to know how this project changed mbed SDK to support Infinity keyboard.

Then, edit makefile to build TMK with mbed SDK and you files. You will be able to know it from Infinity's makefiles.
See keyboard/infinity/mbed-infinity.mk and tmk_core/tool/mbed/{mbed|common|gcc}.mk.

EDIT: FYI, Infinity is keyboard which uses Freescale MK20DX128VLF5 as controller. https://www.massdrop.com/buy/infinity-keyboard-kit

User avatar
Ray

02 May 2015, 17:11

Well, I did delve quite into this firmware, but still don't grasp the big theme of it. Maybe it is because I try to avoid looking into USB-stack or other protocols.

If I want to check once after connecting if numlock is set on the computer - and if it isn't, sent a numlock press - where should I do that?

On another note, I want a command to be executed on every keypress except on modifiers (if I could exclude more keys, that's fine too). Where is a nice place to do this? I tried in action.c where it says /* Key and Mods */ after the if(mods) I tried an else, but this gets executed on any keypress still...

On yet another note, I tried to implement something similar to the shift-parantheses in the hhkb/keymap_hasu.c "example". But that code doesn't work for me, it always produces shift, on hold or tap, doesn't matter.
EDIT: okay, this one was simply stupid by me. ACTION_FUNCTION_TAP is correct here, when I tried ACTION_FUNCTION...

brunci4136

06 May 2015, 12:05

Would this work with Pro Micro board?
Thinking about getting this one
http://www.ebay.com/itm/Leonardo-Pro-Mi ... 4853468c6a

User avatar
Ray

06 May 2015, 16:33

Yes, the Pro Micro has the same MCU as the Teensy, so from the software-side it is no concern.
You have less pins available though, probably not enough for connecting a keyboard-matrix. But if you want to make a converter that's not an issue. And you have to figure out the AVR-pinnames for the Leonardo-pinnames, but you can find that with google.

brunci4136

06 May 2015, 19:36

Would i have enough pins for this layout?

Image

http://www.keyboard-layout-editor.com/# ... e025b72844

And what converter are you talking about?

User avatar
Ray

06 May 2015, 20:15

with that layout (62 Keys?) your matrix alone will need 16 pins at least and about 19 if you don't want to be too crazy with the matrix layout

the leonardo pro micro board has 18 pins available for you. So it depends on what features you want to have and how hard you want to wrap your brain while wiring the matrix.
E.g. if you only put Enter and Delete on the bottom row of your matrix and the rest quite intuitively, that's 18 pins. You wouldn't have LEDS for Capslock or anything (which is fine if you don't want).

You are also lacking the luxury of a reset pushbutton for flashing. But you could add one even accessable when the keyboard is closed. This does not take an I/O pin.

But I am not sure if you can flash this firmware with the Arduino Bootloader. You probably can, not sure. Maybe someone else can clarify this.

I would advise the Teensy, because a lot of info here is directed for the teensy. And what is 10 bucks when it saves you time. But if you don't mind spending 110hours instead of 100hours (well, depending on the features again), then you can probably save 10 bucks, yes.
My custom built needs only 12 pins for the matrix (+2 for my trackpoint +another optional 2 for LEDS), but I don't regret that I bought the teensy for it.

I did mention the converter, because you didn't exactly specify your project. Hasu's firmware can also be used for converters from some older keyboard protocols to USB. Those generally don't need many pins.

brunci4136

06 May 2015, 22:14

Thanks for help! :D :D
First time building so I am a bit noob.

secretv

07 May 2015, 08:52

I just wanted to say thank you for this amazing guide. A few things would make it easier for noobs like myself. Add the ((matrix_row_t) information for defining keyboards with more than 16 columns and the binary notation for more than 16 keys KC_##K010. The LED portion appears to be incorrect. I used the following to get mine to work.

void led_set(uint8_t usb_led)
{
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
// Output High
DDRD |= (1<<4);
PORTD |= (1<<4);
} else {
// Output Low
DDRD &= ~(1<<4);
PORTD &= ~(1<<4);
}

gunnarbiymlol

10 Jun 2015, 15:43

Hello. I am currently working on a keyboard for a school project. I have gotten to the compile step, but when I try and do the "make -f Makefile" it tells me that it is an unknown command.

My Question is is there anyway to get "gh60_lufa.hex" as the computer is right now or do I need to download a program?

User avatar
Muirium
µ

10 Jun 2015, 16:37

Yes there is. Use this:

http://www.pjrc.com/teensy/loader.html

I've no idea about your other question. I only ever use pre-rolled firmwares built by other people because whenever I code, things catch fire.

gunnarbiymlol

10 Jun 2015, 19:30

Hey Muirium,

Thanks for the response. Sorry if my question was unclear.

The problem I am having is I am not sure how to get the gh60_lufa.hex file.
In the in instructions it says to "Open the terminal go to the gh60 directory and run: make -f Makefile, If you did everything fine you'll end up with a file called gh60_lufa.hex.".

I get an message saying it does not recognize the command when I do make -f Makefile.
Is this because I made an error in my code. My teacher said it was because the computers do not have the ability to do that command.

Again, thanks for your help!

User avatar
Muirium
µ

10 Jun 2015, 19:38

Your teacher hasn't heard of makefiles. I'm no coder, absolutely seriously! So you really need someone else to chime in here. But when things are set up right you do indeed build things with the make command.

Building from source: not for everyone!

User avatar
HzFaq

10 Jun 2015, 19:41

Are you on Windows? If so, you need to download winavr to get the make command. Then you just open a command window, do your "make -f makefile" bit and it should compile.

Not sure if you're not on Windows, I'm sure one of the other Linux/Mac guys can help.

User avatar
HunterH

17 Jun 2015, 02:33

Good day.

As do a large number of people posting on this thread, I have a problem with my firmware.

Currently running on Windows 7, 64bit.
I am able to create the HEX file from the freshly unzipped source.

When I try to run my changed version, however, I encounter problems. :shock:

Here is the output of the console: :?
Spoiler:

Code: Select all

C:\Users\Hunter\Desktop\tmk_keyboard-master\keyboard\gh60>make
/usr/bin/sh: dfu-programmer: command not found
/usr/bin/sh: dfu-programmer: command not found

-------- begin --------
avr-gcc (WinAVR 20100110) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


mkdir -p obj_gh60_lufa
Compiling C: keymap_poker.c
avr-gcc -c -mmcu=atmega32u4 -gdwarf-2 -DF_CPU=16000000UL -DINTERRUPT_CONTROL_END
POINT -DBOOTLOADER_SIZE=4096 -DF_USB=16000000UL -DARCH=ARCH_AVR8 -DUSB_DEVICE_ON
LY -DUSE_FLASH_DESCRIPTORS -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB
_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" -DFIXED_CONTROL_ENDPOINT_SIZE=8  -DFIXED_N
UM_CONFIGURATIONS=1 -DPROTOCOL_LUFA -DBOOTMAGIC_ENABLE -DMOUSEKEY_ENABLE -DMOUSE
_ENABLE -DEXTRAKEY_ENABLE -DCONSOLE_ENABLE -DCOMMAND_ENABLE -DNKRO_ENABLE -DVERS
ION=unknown -Os -funsigned-char -funsigned-bitfields -ffunction-sections -fdata-
sections -fno-inline-small-functions -fpack-struct -fshort-enums -fno-strict-ali
asing -Wall -Wstrict-prototypes -Wa,-adhlns=obj_gh60_lufa/keymap_poker.lst -I. -
I../../tmk_core -I../../tmk_core/protocol/lufa -I../../tmk_core/protocol/lufa/LU
FA-git -I../../tmk_core/common -std=gnu99 -include config.h -MMD -MP -MF .dep/ob
j_gh60_lufa_keymap_poker.o.d  keymap_poker.c -o obj_gh60_lufa/keymap_poker.o
In file included from keymap_poker.c:2:
keymap_common.h:38:5: error: macro parameters must be comma-separated
keymap_poker.c:8: warning: implicit declaration of function 'KEYMAP'
keymap_poker.c:8: error: 'ESC' undeclared here (not in a function)
keymap_poker.c:8: error: 'I' undeclared here (not in a function)
keymap_poker.c:9: error: 'TAB' undeclared here (not in a function)
keymap_poker.c:9: error: 'Q' undeclared here (not in a function)
keymap_poker.c:9: error: 'W' undeclared here (not in a function)
keymap_poker.c:9: error: 'E' undeclared here (not in a function)
keymap_poker.c:9: error: 'R' undeclared here (not in a function)
keymap_poker.c:9: error: 'T' undeclared here (not in a function)
keymap_poker.c:9: error: 'J' undeclared here (not in a function)
keymap_poker.c:10: error: 'A' undeclared here (not in a function)
keymap_poker.c:10: error: 'S' undeclared here (not in a function)
keymap_poker.c:10: error: 'D' undeclared here (not in a function)
keymap_poker.c:10: error: 'F' undeclared here (not in a function)
keymap_poker.c:10: error: 'G' undeclared here (not in a function)
keymap_poker.c:10: error: 'C' undeclared here (not in a function)
keymap_poker.c:11: error: 'LSFT' undeclared here (not in a function)
keymap_poker.c:11: error: 'O' undeclared here (not in a function)
keymap_poker.c:11: error: 'P' undeclared here (not in a function)
keymap_poker.c:11: error: 'B' undeclared here (not in a function)
keymap_poker.c:11: error: 'X' undeclared here (not in a function)
keymap_poker.c:12: error: 'LCTL' undeclared here (not in a function)
keymap_poker.c:12: error: 'FN0' undeclared here (not in a function)
keymap_poker.c:12: error: 'L' undeclared here (not in a function)
keymap_poker.c:12: error: 'SPC' undeclared here (not in a function)
keymap_poker.c:12: error: 'Z' undeclared here (not in a function)
keymap_poker.c:8: warning: missing braces around initializer
keymap_poker.c:8: warning: (near initialization for 'keymaps[0]')
keymap_poker.c:8: error: initializer element is not constant
keymap_poker.c:8: error: (near initialization for 'keymaps[0][0][0]')
keymap_poker.c:16: error: 'TRNS' undeclared here (not in a function)
keymap_poker.c:16: error: 'F1' undeclared here (not in a function)
keymap_poker.c:16: error: 'F2' undeclared here (not in a function)
keymap_poker.c:16: error: 'F3' undeclared here (not in a function)
keymap_poker.c:16: error: 'F4' undeclared here (not in a function)
keymap_poker.c:16: error: 'F5' undeclared here (not in a function)
keymap_poker.c:16: error: 'F6' undeclared here (not in a function)
keymap_poker.c:16: error: 'F7' undeclared here (not in a function)
keymap_poker.c:17: error: 'F8' undeclared here (not in a function)
keymap_poker.c:18: error: 'F9' undeclared here (not in a function)
keymap_poker.c:19: error: 'F10' undeclared here (not in a function)
keymap_poker.c:20: error: 'F11' undeclared here (not in a function)
keymap_poker.c:16: error: initializer element is not constant
keymap_poker.c:16: error: (near initialization for 'keymaps[0][0][1]')
make: *** [obj_gh60_lufa/keymap_poker.o] Error 1

C:\Users\Hunter\Desktop\tmk_keyboard-master\keyboard\gh60>
I was unable to find someone else with this error, or a solution!

Here are the files that I have edited as per the instructional segment at the beginning of this thread.


--


Makefile:
Spoiler:

Code: Select all

#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device.
#                Please customize your programmer settings(PROGRAM_CMD)
#
# make teensy = Download the hex file to the device, using teensy_loader_cli.
#               (must have teensy_loader_cli installed).
#
# make dfu = Download the hex file to the device, using dfu-programmer (must
#            have dfu-programmer installed).
#
# make flip = Download the hex file to the device, using Atmel FLIP (must
#             have Atmel FLIP installed).
#
# make dfu-ee = Download the eeprom file to the device, using dfu-programmer
#               (must have dfu-programmer installed).
#
# make flip-ee = Download the eeprom file to the device, using Atmel FLIP
#                (must have Atmel FLIP installed).
#
# make debug = Start either simulavr or avarice as specified for debugging, 
#              with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
#                   bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------

# Target file name (without extension).
TARGET = gh60_lufa

# Directory common source filess exist
TMK_DIR = ../../tmk_core

# Directory keyboard dependent files exist
TARGET_DIR = .

# project specific files
SRC =	keymap_common.c \
	matrix.c \
	led.c

ifdef KEYMAP
    SRC := keymap_$(KEYMAP).c $(SRC)
else
    SRC := keymap_poker.c $(SRC)
endif

CONFIG_H = config.h


# MCU name
#MCU = at90usb1287
MCU = atmega32u4

# Processor frequency.
#     This will define a symbol, F_CPU, in all source code files equal to the
#     processor frequency in Hz. You can then use this symbol in your source code to
#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done
#     automatically to create a 32-bit value in your source code.
#
#     This will be an integer division of F_USB below, as it is sourced by
#     F_USB after it has run through any CPU prescalers. Note that this value
#     does not *change* the processor frequency - it should merely be updated to
#     reflect the processor speed set externally so that the code can use accurate
#     software delays.
F_CPU = 16000000


#
# LUFA specific
#
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8

# Input clock frequency.
#     This will define a symbol, F_USB, in all source code files equal to the
#     input clock frequency (before any prescaling is performed) in Hz. This value may
#     differ from F_CPU if prescaling is used on the latter, and is required as the
#     raw input clock is fed directly to the PLL sections of the AVR for high speed
#     clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
#     at the end, this will be done automatically to create a 32-bit value in your
#     source code.
#
#     If no clock division is performed on the input clock inside the AVR (via the
#     CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_USB = $(F_CPU)

# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT


# Boot Section Size in *bytes*
#   Teensy halfKay   512
#   Teensy++ halfKay 1024
#   Atmel DFU loader 4096
#   LUFA bootloader  4096
#   USBaspLoader     2048
OPT_DEFS += -DBOOTLOADER_SIZE=4096


# Build Options
#   comment out to disable the options.
#
BOOTMAGIC_ENABLE = yes	# Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = yes	# Mouse keys(+4700)
EXTRAKEY_ENABLE = yes	# Audio control and System control(+450)
CONSOLE_ENABLE = yes	# Console for debug(+400)
COMMAND_ENABLE = yes    # Commands for debug and configuration
#SLEEP_LED_ENABLE = yes  # Breathing sleep LED during USB suspend
#NKRO_ENABLE = yes	# USB Nkey Rollover - not yet supported in LUFA


# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax

# Search Path
VPATH += $(TARGET_DIR)
VPATH += $(TMK_DIR)

include $(TMK_DIR)/protocol/lufa.mk
include $(TMK_DIR)/common.mk
include $(TMK_DIR)/rules.mk
--

config.h
Spoiler:

Code: Select all

/*
Copyright 2012 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef CONFIG_H
#define CONFIG_H


/* USB Device descriptor parameter */
#define VENDOR_ID       0xFEED
#define PRODUCT_ID      0x6060
#define DEVICE_VER      0x0001
#define MANUFACTURER    HunterH
#define PRODUCT         Dank CS:GO Keyboard
#define DESCRIPTION     A dank keyboard for use with CS:GO and other games.

/* key matrix size */
#define MATRIX_ROWS 5
#define MATRIX_COLS 8

/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST

/* Set 0 if debouncing isn't needed */
#define DEBOUNCE    5

/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE

/* key combination for command */
#define IS_COMMAND() ( \
    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)



/*
 * Feature disable options
 *  These options are also useful to firmware size reduction.
 */

/* disable debug print */
//#define NO_DEBUG

/* disable print */
//#define NO_PRINT

/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
//#define NO_ACTION_MACRO
//#define NO_ACTION_FUNCTION

#endif
--

matrix.c
Spoiler:

Code: Select all

/*
Copyright 2012 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * scan matrix
 */
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
#include "util.h"
#include "matrix.h"


#ifndef DEBOUNCE
#   define DEBOUNCE	5
#endif
static uint8_t debouncing = DEBOUNCE;

/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];

static matrix_row_t read_cols(void);
static void init_cols(void);
static void unselect_rows(void);
static void select_row(uint8_t row);


inline
uint8_t matrix_rows(void)
{
    return MATRIX_ROWS;
}

inline
uint8_t matrix_cols(void)
{
    return MATRIX_COLS;
}

void matrix_init(void)
{
    // initialize row and col
    unselect_rows();
    init_cols();

    // initialize matrix state: all keys off
    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
        matrix[i] = 0;
        matrix_debouncing[i] = 0;
    }
}

uint8_t matrix_scan(void)
{
    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
        select_row(i);
        _delay_us(30);  // without this wait read unstable value.
        matrix_row_t cols = read_cols();
        if (matrix_debouncing[i] != cols) {
            matrix_debouncing[i] = cols;
            if (debouncing) {
                debug("bounce!: "); debug_hex(debouncing); debug("\n");
            }
            debouncing = DEBOUNCE;
        }
        unselect_rows();
    }

    if (debouncing) {
        if (--debouncing) {
            _delay_ms(1);
        } else {
            for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
                matrix[i] = matrix_debouncing[i];
            }
        }
    }

    return 1;
}

bool matrix_is_modified(void)
{
    if (debouncing) return false;
    return true;
}

inline
bool matrix_is_on(uint8_t row, uint8_t col)
{
    return (matrix[row] & ((matrix_row_t)1<<col));
}

inline
matrix_row_t matrix_get_row(uint8_t row)
{
    return matrix[row];
}

void matrix_print(void)
{
    print("\nr/c 0123456789ABCDEF\n");
    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
        phex(row); print(": ");
        pbin_reverse16(matrix_get_row(row));
        print("\n");
    }
}

uint8_t matrix_key_count(void)
{
    uint8_t count = 0;
    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
        count += bitpop16(matrix[i]);
    }
    return count;
}

/* Column pin configuration
 * col: 0   1   2   3   4   5   6   7   8   9   10  11  12  13
 * pin: F0  F1  E6  C7  C6  B6  D4  B1  B0  B5  B4  D7  D6  B3  (Rev.A)
 * pin:                                 B7                      (Rev.B)
 */
static void  init_cols(void)
{
    // Input with pull-up(DDR:0, PORT:1)
    DDRF  &= ~(1<<7);
    PORTF |=  (1<<7);
    DDRB  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3 | 1<<2 1<<1);
    PORTB |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3 | 1<<2 1<<1);

}

static matrix_row_t read_cols(void)
{
    return (PINF&(1<<7) ? 0 : (1<<0)) |
           (PINB&(1<<7) ? 0 : (1<<1)) |
           (PINB&(1<<6) ? 0 : (1<<2)) |
           (PINB&(1<<5) ? 0 : (1<<3)) |
           (PINB&(1<<4) ? 0 : (1<<4)) |
           (PINB&(1<<3) ? 0 : (1<<5)) |
           (PINB&(1<<2) ? 0 : (1<<6)) |
           (PINB&(1<<1) ? 0 : (1<<7));
}

/* row:  0   1   2   3   4
	pin: F0  F1  F4  F5  F6
 */
static void unselect_rows(void)
{
    // Hi-Z(DDR:0, PORT:0) to unselect
    DDRF  &= ~0b01110011;
    PORTF &= ~0b01110011;
}

static void select_row(uint8_t row)
{
    // Output low(DDR:1, PORT:0) to select
    switch (row) {
        case 0:
            DDRF  |= (1<<0);
            PORTF &= ~(1<<0);
            break;
        case 1:
            DDRF  |= (1<<1);
            PORTF &= ~(1<<1);
            break;
        case 2:
            DDRF  |= (1<<4);
            PORTF &= ~(1<<4);
            break;
        case 3:
            DDRF  |= (1<<5);
            PORTF &= ~(1<<5);
            break;
        case 4:
            DDRF  |= (1<<6);
            PORTF &= ~(1<<6);
            break;
    }
}
--


keymap_common.h
Spoiler:

Code: Select all

/*
Copyright 2012,2013 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEYMAP_COMMON_H
#define KEYMAP_COMMON_H

#include <stdint.h>
#include <stdbool.h>
#include <avr/pgmspace.h>
#include "keycode.h"
#include "action.h"
#include "action_macro.h"
#include "report.h"
#include "host.h"
#include "print.h"
#include "debug.h"
#include "keymap.h"


extern const uint8_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
extern const uint16_t fn_actions[];

#define KEYMAP( \
    K00, K01, K02, K03, K04, K05, K06, K07 \
    K10,      K12, K13, K14, K15, K16, K17 \
              K22, K23, K24, K25, K26, K27 \
    K30,      K32, K33,           K36, K37 \
    K40,      K42, K43,      K45,      K47 \
) { \
    { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \
    { KC_##K10, KC_NO,    KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \
    { KC_NO,    KC_NO,    KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \
    { KC_##K30, KC_NO,    KC_##K32, KC_##K33, KC_NO,    KC_NO,    KC_##K36, KC_##K37 }, \
    { KC_##K40, KC_NO,    KC_##K42, KC_##K43, KC_NO,    KC_##K45, KC_NO,    KC_##K47 }  \
}

#endif
--

keymap_poker.c
Spoiler:

Code: Select all

#include "keymap_common.h"

const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    
	
	/* 0: qwerty */
	KEYMAP(ESC,   1,   2,   3,   4,   5,   6,   I, \
	       TAB,        Q,   W,   E,   R,   T,   J, \
		               A,   S,   D,   F,   G,   C, \
           LSFT,       O,   P,             B,   X, \
		   LCTL,       FN0, L,        SPC,      Z),
	
	
	/* 1: FN 1 */
	KEYMAP(TRNS, F1,  F2,  F3,  F4,  F5,  F6,  F7, \
	       TRNS,      TRNS,TRNS,TRNS,TRNS,TRNS,F8, \
		              TRNS,TRNS,TRNS,TRNS,TRNS,F9, \
	       TRNS,      TRNS,TRNS,           TRNS,F10, \
		   TRNS,      TRNS,TRNS,     TRNS,      F11), \
		   
	
};
const uint16_t PROGMEM fn_actions[] = {

	[0] = ACTION_LAYER_MOMENTARY(1),
	[1] = ACTION_LAYER_TAP_KEY(1, KC_K),
    
};


Hopefully this is a simple error to fix! :roll:

Thanks to the keyboard community for getting me this far already! :D

-Hunter

User avatar
Ray

17 Jun 2015, 13:43

“keymap_common.h:38:5: error: macro parameters must be comma-separated” is the relevant error

in your keymap_common.h in the keymap macro, you need a comma near the end of the lines, before the backslash

User avatar
Halvar

17 Jun 2015, 13:50

Hi HunterH,

go to the first actual error message and look for where it comes from. When you have found and corrected one error, recompile, because with C, many error messages are just following from errors that were found earlier.

First one is:
keymap_common.h:38:5: error: macro parameters must be comma-separated

which comes from missing commas at the end of the lines in the macro definition for the keymap macro. So in keymap_common.h, try correcting it like this:

Code: Select all

#define KEYMAP( \
    K00, K01, K02, K03, K04, K05, K06, K07, \
    K10,      K12, K13, K14, K15, K16, K17, \
              K22, K23, K24, K25, K26, K27, \
    K30,      K32, K33,           K36, K37, \
    K40,      K42, K43,      K45,      K47 \
) { \
    { KC_##K00, KC_##K01, KC_##K02, KC_##K03, KC_##K04, KC_##K05, KC_##K06, KC_##K07 }, \
    { KC_##K10, KC_NO,    KC_##K12, KC_##K13, KC_##K14, KC_##K15, KC_##K16, KC_##K17 }, \
    { KC_NO,    KC_NO,    KC_##K22, KC_##K23, KC_##K24, KC_##K25, KC_##K26, KC_##K27 }, \
    { KC_##K30, KC_NO,    KC_##K32, KC_##K33, KC_NO,    KC_NO,    KC_##K36, KC_##K37 }, \
    { KC_##K40, KC_NO,    KC_##K42, KC_##K43, KC_NO,    KC_##K45, KC_NO,    KC_##K47 }  \
}
The rest of the errors (or most of them) might go away if you correct that.

User avatar
HunterH

17 Jun 2015, 18:09

Success!!!

I fixed the commas, then one other little error and it compiled!

I have learned to tackle errors chronologically as opposed to trying to attack the biggest chunk. :roll:

Thank you two for you help; I really appreciate it! :D :D :D :D

User avatar
LeandreN

20 Jun 2015, 21:32

Hey Matt3o. I am a completely noob to software and tried the best i could to follow your tutotial. Some basic things, like the binary step, i could simply not understand, even how clear you were trying to make it. Well, after a long time, i made it through the tutorial, but it won't make the Hex file. Some assistance would be very appericated.


Image



keymap_poker

Code: Select all

#include "keymap_common.h"

const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
	/*0: qwerty*/
	KEYMAP(1, 2, 3, 4, \
	LEFT, RGHT, \
	FN1, ENT \
	5, 6, 7, 8, \
	9, 0, COMM, DOT),
	/*1: FN1*/
	KEYMAP(F1, F2, F3, F4 \
	EQL, MINS,\
	TRNS, ENT,\
	F5, F6, F7, F8, \
	F9, F10, F11, F12),
	
	
	
	)

};

const uint16_t PROGMEM fn_actions[] = {
	[0] = ACTION_LAYER_MOMENTARY(1),

};
Matrix

Code: Select all

/*
Copyright 2012 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/*
 * scan matrix
 */
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
#include "util.h"
#include "matrix.h"


#ifndef DEBOUNCE
#   define DEBOUNCE	5
#endif
static uint8_t debouncing = DEBOUNCE;

/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];

static matrix_row_t read_cols(void);
static void init_cols(void);
static void unselect_rows(void);
static void select_row(uint8_t row);


inline
uint8_t matrix_rows(void)
{
    return MATRIX_ROWS;
}

inline
uint8_t matrix_cols(void)
{
    return MATRIX_COLS;
}

void matrix_init(void)
{
    // initialize row and col
    unselect_rows();
    init_cols();

    // initialize matrix state: all keys off
    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
        matrix[i] = 0;
        matrix_debouncing[i] = 0;
    }
}

uint8_t matrix_scan(void)
{
    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
        select_row(i);
        _delay_us(30);  // without this wait read unstable value.
        matrix_row_t cols = read_cols();
        if (matrix_debouncing[i] != cols) {
            matrix_debouncing[i] = cols;
            if (debouncing) {
                debug("bounce!: "); debug_hex(debouncing); debug("\n");
            }
            debouncing = DEBOUNCE;
        }
        unselect_rows();
    }

    if (debouncing) {
        if (--debouncing) {
            _delay_ms(1);
        } else {
            for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
                matrix[i] = matrix_debouncing[i];
            }
        }
    }

    return 1;
}

bool matrix_is_modified(void)
{
    if (debouncing) return false;
    return true;
}

inline
bool matrix_is_on(uint8_t row, uint8_t col)
{
    return (matrix[row] & ((matrix_row_t)1<<col));
}

inline
matrix_row_t matrix_get_row(uint8_t row)
{
    return matrix[row];
}

void matrix_print(void)
{
    print("\nr/c 0123456789ABCDEF\n");
    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
        phex(row); print(": ");
        pbin_reverse16(matrix_get_row(row));
        print("\n");
    }
}

uint8_t matrix_key_count(void)
{
    uint8_t count = 0;
    for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
        count += bitpop16(matrix[i]);
    }
    return count;
}

/* Column pin configuration
 * col: 0   1   2   3   4   5   6   7   8   9   10  11  12  13
 * pin: F5  F4  F1  F0  C6  B6  D4  B1  B0  B5  B4  D7  D6  B3  (Rev.A)
 * pin:                                 B7                      (Rev.B)
 */
static void  init_cols(void)
{
    // Input with pull-up(DDR:0, PORT:1)
    DDRF  &= ~(1<<5 | 1<<4 | 1<<1 | 1<<0);
	PORTF |= (1<<5 | 1<<4 | 1<<1 | 1<<0);
}

static matrix_row_t read_cols(void)
{
    return (PINF&(1<<5) ? 0 : (1<<0)) |
           (PINF&(1<<4) ? 0 : (1<<1)) |
           (PINE&(1<<1) ? 0 : (1<<2)) |
           (PINC&(1<<0) ? 0 : (1<<3)) |
           (PINC&(1<<6) ? 0 : (1<<4)) |
           (PINB&(1<<6) ? 0 : (1<<5)) |
           (PIND&(1<<4) ? 0 : (1<<6)) |
           (PINB&(1<<1) ? 0 : (1<<7)) |
           ((PINB&(1<<0) && PINB&(1<<7)) ? 0 : (1<<8)) |     // Rev.A and B
           (PINB&(1<<5) ? 0 : (1<<9)) |
           (PINB&(1<<4) ? 0 : (1<<10)) |
           (PIND&(1<<7) ? 0 : (1<<11)) |
           (PIND&(1<<6) ? 0 : (1<<12)) |
           (PINB&(1<<3) ? 0 : (1<<13));
}

/* Row pin configuration
 * row: 0   1   2   3   4
 * pin: D0  D1  D2  D3  D5
 */
static void unselect_rows(void)
{
    // Hi-Z(DDR:0, PORT:0) to unselect
    DDRD  &= ~0b00101111;
    PORTD &= ~0b00101111;
}

static void select_row(uint8_t row)
{
    // Output low(DDR:1, PORT:0) to select
    switch (row) {
        case 0:
            DDRC  |= (1<<6);
            PORTC &= ~(1<<6);
            break;
        case 1:
            DDRD  |= (1<<3);
            PORTD &= ~(1<<3);
            break;
        case 2:
            DDRD  |= (1<<2);
            PORTD &= ~(1<<2);
            break;
        case 3:
            DDRD  |= (1<<1);
            PORTD &= ~(1<<1);
            break;
        case 4:
            DDRD  |= (1<<0);
            PORTD &= ~(1<<0);
            break;
    }
}
config

Code: Select all

/*
Copyright 2012 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef CONFIG_H
#define CONFIG_H


/* USB Device descriptor parameter */
#define VENDOR_ID       0xFEED
#define PRODUCT_ID      0x6060
#define DEVICE_VER      0x0001
#define MANUFACTURER    geekhack
#define PRODUCT         GH60
#define DESCRIPTION     t.m.k. keyboard firmware for GH60

/* key matrix size */
#define MATRIX_ROWS 5
#define MATRIX_COLS 4

/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST

/* Set 0 if debouncing isn't needed */
#define DEBOUNCE    5

/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE

/* key combination for command */
#define IS_COMMAND() ( \
    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)



/*
 * Feature disable options
 *  These options are also useful to firmware size reduction.
 */

/* disable debug print */
//#define NO_DEBUG

/* disable print */
//#define NO_PRINT

/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
//#define NO_ACTION_MACRO
//#define NO_ACTION_FUNCTION

#endif
Thanks for all help i can get.

User avatar
flabbergast

20 Jun 2015, 22:30

The problem is not with TMK source code (at least not according to the error message you're getting), but (probably) with your avr-gcc installation and/or memory and/or limit on the number of opened files or something like that. Very weird error - not related to the source code, but with the compiler trying to fork and not being able to (that's something that it normally does quite a lot). You can read more about forking here: https://en.wikipedia.org/wiki/Fork_(system_call) - but it's actually probably irrelevant to your problem...

What I would try to do is some "standard" stuff, like rebooting the machine, etc...
If you feel OK with virtual machines, it might save you some headaches in the long run to have a linux running on one - but on the other hand, people succeed with compiling on windows as well.

EDIT: Forgot to say - it's probably best, as a first step, to compile "clean" TMK (for any keyboard/layout), i.e. to compile something _before_ you edit anything in the sources. That should work. If it doesn't, it's likely there's a problem with the compiler itself.

User avatar
LeandreN

21 Jun 2015, 00:15

Hmm, I have tried two different computers and I still get the same message. Also, do the binary stuff in the matrix file look strange to you, I couldn't understand what I should do.
Thanks for your response though. I hope I can fix this together with you.

User avatar
scottc

21 Jun 2015, 02:26

To me it sounds like you might've set up something that caused an infinite loop. Did you include your keymap within your keymap definition or something like that? Maybe copy a fresh version of the source code and apply your changes bit by bit to see what causes that error.

User avatar
flabbergast

21 Jun 2015, 10:09

scottc wrote: To me it sounds like you might've set up something that caused an infinite loop. Did you include your keymap within your keymap definition or something like that? Maybe copy a fresh version of the source code and apply your changes bit by bit to see what causes that error.
I would think that compilers can deal with this kind of problems. Also - the first complaint about fork is actually _before_ the compiler runs (before ---begin---). But you may be right.

LeandreN - you should definitely try compiling first without any modification to sources.

User avatar
flabbergast

21 Jun 2015, 10:31

I had a look at your matrix.c as well - I can't be more specific since I don't know your keyboard matrix. If send me the wiring (which cols are connected to which pins) I can check it.

The way it's now, you only have 4 columns (that are set up in init_cols), but then read_cols doesn't match that, since it's testing for a bunch of other pins as well. init_cols sets up which pins are connected to columns, and read_cols is used periodically to check the status. The same pins should appear in both functions.
The same goes for unselect_rows and select_row. This is also not so in your source - unselect_rows uses PD0, PD1, PD2, PD3, PD5 (PORTD, bits 0,1,2,3,5), while select_row deals with PD0, PD1, PD2, PD3 (PORTD, bits 0,1,2,3) and PC6 (PORTC, bit 6).

So for instance, assuming select_row does the bits that you actually want, unselect_rows should contain

Code: Select all

// Hi-Z(DDR:0, PORT:0) to unselect
DDRD  &= ~0b00001111;
PORTD &= ~0b00001111;
DDRC &= ~0b01000000;
PORTC &= ~0b01000000;

User avatar
scottc

21 Jun 2015, 10:37

flabbergast wrote:
scottc wrote: To me it sounds like you might've set up something that caused an infinite loop. Did you include your keymap within your keymap definition or something like that? Maybe copy a fresh version of the source code and apply your changes bit by bit to see what causes that error.
I would think that compilers can deal with this kind of problems. Also - the first complaint about fork is actually _before_ the compiler runs (before ---begin---). But you may be right.

LeandreN - you should definitely try compiling first without any modification to sources.
Oh, good point. I didn't read the output very carefully but it does indeed look like the error is from Make, not the compiler. So I agree - try to compile the firmware without any changes first.

I searched around a bit for this error and it was hinted that it might be a dodgy GCC-AVR install.

User avatar
Bhuyakasha

23 Jun 2015, 16:04

Hey, any tips for debugging?

My keyboard spams 6 keys, of which 5 are on the same row. I have tried resoldering the row to a different pin but that didn't help. I'd think that it's a hardware problem of shorts, but I checked everything with a multimeter and there don't seem to be any. Can this be a software problem instead?

Link to my code:
https://www.dropbox.com/sh/uw07aa3kiej9 ... VlP3a?dl=0

Regards <3

Edit: Never mind guys, I am typing on it right now! There was a syntax error in the declaration of the pins as well as a mixup between two pins. I'm so giddy!

gangolfus

25 Jun 2015, 17:47

Hello Gurus - I'm having an issue with this firmware and I am hoping someone can point me in the right direction.

For one of my columns, when I press the top key, the rest of the keys in that column also fire.
eg, Press F5: F5/6/y/g/b all fire

I am also having a similar problem another column, but where all the keys in the row after fire.
eg. Press Right Arrow: Right Arrow/0/./Enter all fire

Do these sound like programming problems or electrical problems?

Any guidance is greatly appreciated!

EDIT: For those who might find this in the future, the first issue appears to have been caused by a short. The second issue: Apparently if you have more than 14 columns, all columns past 14 must us 1UL in read_cols function.
eg
static matrix_row_t read_cols(void)
{
return (PINE&(1<<1) ? 0 : (1<<0)) |
(PINC&(1<<2) ? 0 : (1<<1)) |
(PINC&(1<<1) ? 0 : (1<<2)) |
(PINB&(1<<0) ? 0 : (1<<3)) |
(PINE&(1<<7) ? 0 : (1<<4)) |
(PINE&(1<<6) ? 0 : (1<<5)) |
(PINF&(1<<0) ? 0 : (1<<6)) |
(PINF&(1<<1) ? 0 : (1<<7)) |
(PINF&(1<<2) ? 0 : (1<<8)) |
(PINF&(1<<3) ? 0 : (1<<9)) |
(PINF&(1<<4) ? 0 : (1<<10)) |
(PINF&(1<<5) ? 0 : (1<<11)) |
(PINF&(1<<6) ? 0 : (1<<12)) |
(PINF&(1<<7) ? 0 : (1<<13)) |
(PINE&(1<<0) ? 0 : (1<<14)) |
(PINC&(1<<3) ? 0 : (1UL<<15)) |
(PINB&(1<<6) ? 0 : (1UL<<16)) |
(PINB&(1<<5) ? 0 : (1UL<<17)) |
(PINB&(1<<4) ? 0 : (1UL<<18)) |
(PINB&(1<<3) ? 0 : (1UL<<19));
}

I incorrectly assumed that only 16 and above needed 1UL.
Last edited by gangolfus on 27 Jun 2015, 06:45, edited 2 times in total.

Post Reply

Return to “Workshop”