This commit is contained in:
Jack Humbert
2018-09-19 23:27:13 -04:00
parent 23da333ae3
commit c49e7e01ab
10 changed files with 843 additions and 2 deletions

View File

@ -13,7 +13,7 @@ const keypos_t hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
__attribute__ ((weak))
void matrix_init_kb(void) {
// Turn status LED on
#ifdef __AVR__
#if defined(__AVR__) && defined(DDRE)
DDRE |= (1<<6);
PORTE |= (1<<6);
#endif
@ -26,4 +26,4 @@ const uint8_t music_map[MATRIX_ROWS][MATRIX_COLS] = LAYOUT_planck_grid(
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
);
);

View File

@ -0,0 +1,71 @@
# jj40
![jj40](https://ae01.alicdn.com/kf/HTB18bq6bOERMeJjSspiq6zZLFXar.jpg?size=359506&height=562&width=750&hash=663a22d0109e2416ec8f54a7658686da)
A compact 40% (12x4) ortholinear keyboard kit made and KPRepublic on AliExpress.
Keyboard Maintainer: [QMK Community](https://github.com/qmk)
Hardware Supported: Atmega32A
Hardware Availability: [AliExpress](https://www.aliexpress.com/store/product/jj40-Custom-Mechanical-Keyboard-40-PCB-programmed-40-planck-layouts-bface-firmware-gh40/3034003_32828781103.html)
Make example for this keyboard (after setting up your build environment):
make jj40:default:program
See [build environment setup](https://docs.qmk.fm/build_environment_setup.html) then the [make instructions](https://docs.qmk.fm/make_instructions.html) for more information.
Note that this is a complete replacement for the firmware, so you won't be
using Bootmapper Client to change any keyboard settings, since not all the
USB report options are supported.
In addition you may need the AVR toolchain and `bootloadHID` ([GitHub repo](https://github.com/whiteneon/bootloadHID)) for flashing:
For macOS:
```
$ brew cask install crosspack-avr
$ brew install --HEAD https://raw.githubusercontent.com/robertgzr/homebrew-tap/master/bootloadhid.rb
```
For Linux:
```
$ sudo apt install libusb-dev
$ wget https://www.obdev.at/downloads/vusb/bootloadHID.2012-12-08.tar.gz
$ tar -xzf bootloadHID.2012-12-08.tar.gz
$ cd bootloadHID.2012-12-08/commandline
$ make
$ sudo cp bootloadHID /usr/bin
```
In order to use the `./program` script, which can reboot the board into
the bootloader, you'll need Python 2 with PyUSB installed:
```
$ pip install pyusb
```
If you prefer (or are having issues with a `program` flash), you can just build it (`make jj40:<keymap-name>` and flash the firmware (`.hex` file) directly with
`bootloadHID` if you boot the board while holding down `Backspace` (`Top Right Key`) to keep it
in the bootloader:
```
$ make jj40
$ bootloadHID -r jj40_default.hex
```
For Windows 10:
Windows sometimes doesn't recognize the jj40. The easiest way of flashing a new layout is probably using [HIDBootFlash](http://vusb.wikidot.com/project:hidbootflash).
1. Go to Windows Device Manager and find the keyboard (plug it in while holding down `Backspace` (`Top Right Key`)). It can be found under Human Interface Devices or under Keyboards.
2. Go to properties and the Details tab to find the hardware ID. You want the VID and the PID (code after the underscore). Plug them into HIDBootFlash and hit Find Device.
3. Use `make jj40:<keymap-name>` to generate the .hex file in the qmk basis folder. Select the .hex file in HIDBootFlash and press Flash Device.
## Troubleshooting
1. Try plugging the board in while pressing `Backspace` (`Top Right Key`). This will force it
to boot only the bootloader without loading the firmware. Once this is
done, just reflash the board with the original firmware.
2. Sometimes USB hubs can act weird, so try connecting the board directly
to your computer or plugging/unplugging the USB hub.
3. If you get an error such as "Resource Unavailable" when attemting to flash
on Linux, you may want to compile and run `tools/usb_detach.c`. See `tools/README.md`
for more info.

View File

@ -0,0 +1,60 @@
/*
Copyright 2017 Luiz Ribeiro <luizribeiro@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/>.
*/
#include "config_common.h"
#ifndef CONFIG_H
#define CONFIG_H
#define VENDOR_ID 0x6060
#define PRODUCT_ID 0x1001
// TODO: share these strings with usbconfig.h
// Edit usbconfig.h to change these.
#define MANUFACTURER OLKB
#define PRODUCT Planck
/* matrix size */
#define MATRIX_ROWS 4
#define MATRIX_COLS 12
#define MATRIX_ROW_PINS { A7, A6, A5, A4 }
#define MATRIX_COL_PINS { D7, C2, C3, C4, C5, C6, C7, A3, A2, A1, A0, B0 }
/* COL2ROW or ROW2COL */
#define DIODE_DIRECTION COL2ROW
#define BACKLIGHT_LEVELS 12
// #define BACKLIGHT_BREATHING // works, but BL_TOGG might not work
#define TAPPING_TOGGLE 3
#define NO_UART 1
/* RGB underglow */
// The RGB_DI_PIN value seems to be shared between all PS2AVRGB boards.
// The same pin is used on the JJ40, at least.
#define RGBLED_NUM 5
#define RGB_DI_PIN E2 // NOTE: for PS2AVRGB boards, underglow commands are sent via I2C to 0xB0.
#define RGBLIGHT_ANIMATIONS
/* key combination for command */
#define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)))
#undef AUDIO_VOICES
#undef C6_AUDIO
#endif

View File

@ -0,0 +1,145 @@
/*
Copyright 2017 Luiz Ribeiro <luizribeiro@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/>.
*/
#include <avr/io.h>
#include <util/delay.h>
#include "matrix.h"
#ifndef DEBOUNCE
# define DEBOUNCE 5
#endif
// #define MATRIX_ROW_PINS { A7, A6, A5, A4 }
// #define MATRIX_COL_PINS { D7, C2, C3, C4, C5, C6, C7, A3, A2, A1, A0, B0 }
static uint8_t debouncing = DEBOUNCE;
static matrix_row_t matrix[MATRIX_ROWS];
static uint8_t matrix_debouncing[MATRIX_COLS];
void matrix_init(void) {
MCUCSR = (1<<JTD);
MCUCSR = (1<<JTD);
//ADCSRA = 0;
// rows (input)
DDRA &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
PORTA &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
// cols (output)
DDRD |= ((1 << 7));
DDRC |= ((1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
DDRA |= ((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
DDRB |= ((1 << 0));
PORTD &= ~((1 << 7));
PORTC &= ~((1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
PORTA &= ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0));
PORTB &= ~((1 << 0));
// initialize matrix state: all keys off
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
matrix[row] = 0x00;
}
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
matrix_debouncing[col] = 0x00;
}
matrix_init_quantum();
}
uint8_t matrix_scan(void) {
for (uint8_t c = 0; c < MATRIX_COLS; c++) {
switch (c) {
case 0: PORTD |= (1 << 7); break;
case 1: PORTC |= (1 << 2); break;
case 2: PORTC |= (1 << 3); break;
case 3: PORTC |= (1 << 4); break;
case 4: PORTC |= (1 << 5); break;
case 5: PORTC |= (1 << 6); break;
case 6: PORTC |= (1 << 7); break;
case 7: PORTA |= (1 << 3); break;
case 8: PORTA |= (1 << 2); break;
case 9: PORTA |= (1 << 1); break;
case 10: PORTA |= (1 << 0); break;
case 11: PORTB |= (1 << 0); break;
}
_delay_us(5);
uint8_t current_col = (
((PINA & (1 << 7)) ? 1 : 0 ) |
(((PINA & (1 << 6)) ? 1 : 0 ) << 1) |
(((PINA & (1 << 5)) ? 1 : 0 ) << 2) |
(((PINA & (1 << 4)) ? 1 : 0 ) << 3)
);
switch (c) {
case 0: PORTD &= ~(1 << 7); break;
case 1: PORTC &= ~(1 << 2); break;
case 2: PORTC &= ~(1 << 3); break;
case 3: PORTC &= ~(1 << 4); break;
case 4: PORTC &= ~(1 << 5); break;
case 5: PORTC &= ~(1 << 6); break;
case 6: PORTC &= ~(1 << 7); break;
case 7: PORTA &= ~(1 << 3); break;
case 8: PORTA &= ~(1 << 2); break;
case 9: PORTA &= ~(1 << 1); break;
case 10: PORTA &= ~(1 << 0); break;
case 11: PORTB &= ~(1 << 0); break;
}
if (matrix_debouncing[c] != current_col) {
matrix_debouncing[c] = current_col;
debouncing = DEBOUNCE;
}
}
if (debouncing) {
if (--debouncing) {
_delay_ms(1);
} else {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = 0;
for (uint8_t j = 0; j < MATRIX_COLS; j++) {
matrix[i] |= (((matrix_debouncing[j] & (1 << i)) ? 1L : 0 ) << j);
}
}
}
}
matrix_scan_quantum();
return 1;
}
inline matrix_row_t matrix_get_row(uint8_t row) {
return matrix[row];
}
void matrix_print(void) {
}
__attribute__ ((weak))
void matrix_init_user(void) { }
__attribute__ ((weak))
void matrix_scan_user(void) { }

View File

@ -0,0 +1,55 @@
# Copyright 2017 Luiz Ribeiro <luizribeiro@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/>.
# MCU name
MCU = atmega32a
PROTOCOL = VUSB
# unsupported features for now
NO_UART = yes
NO_SUSPEND_POWER_DOWN = yes
# processor frequency
F_CPU = 16000000
# Bootloader
# This definition is optional, and if your keyboard supports multiple bootloaders of
# different sizes, comment this out, and the correct address will be loaded
# automatically (+60). See bootloader.mk for all options.
BOOTLOADER = bootloadHID
# build options
BOOTMAGIC_ENABLE = no
MOUSEKEY_ENABLE = no
EXTRAKEY_ENABLE = yes
CONSOLE_ENABLE = no
COMMAND_ENABLE = yes
KEY_LOCK_ENABLE = yes
NKRO_ENABLE = no # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
AUDIO_ENABLE = no
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
OPT_DEFS = -DDEBUG_LEVEL=0
# custom matrix setup
CUSTOM_MATRIX = yes
SRC = matrix.c
# programming options
PROGRAM_CMD = ./util/atmega32a_program.py $(TARGET).hex
LAYOUTS = ortho_4x12 planck_mit planck_grid

View File

@ -0,0 +1,45 @@
/* Copyright 2018 Jack Humbert <jack.humb@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/>.
*/
#include "thk.h"
void matrix_init_kb(void) {
DDRD |= (1<<5);
//PORTD |= (1<<5);
matrix_init_user();
}
void matrix_scan_kb(void) {
matrix_scan_user();
}
static uint8_t keys_pressed = 0;
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
keys_pressed++;
} else {
keys_pressed--;
}
if (keys_pressed) {
PORTD |= (1<<5);
} else {
PORTD &= ~(1<<5);
}
return process_record_user(keycode, record);
}

View File

@ -0,0 +1,19 @@
/* Copyright 2018 Jack Humbert <jack.humb@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/>.
*/
#pragma once
#include "planck.h"

View File

@ -0,0 +1,16 @@
# JJ40 Tools
## usb_detach.c
When trying to flash on Linux, you may encounter a "Resource Unavailable" error. This means that Linux's HID driver has taken exclusive control of the keyboard, and the program script can't flash it.
This program can force Linux to give up a device, so that the programming script can reset it.
### To compile:
```
gcc usb_detach.c -o usb_detach
```
### To run:
1. Use `lsusb` to discover the Bus and Device numbers for your keyboard.
2. Run the program: `sudo ./usb_detach /dev/bus/usb/<BUS>/<DEVICE>`.
3. Build and program the firmware as normal.

View File

@ -0,0 +1,33 @@
/* Found at https://www.linuxquestions.org/questions/linux-hardware-18/how-to-unclaim-usb-device-558138/#post3406986 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <linux/usbdevice_fs.h>
int main(int argc, char**argv)
{
struct usbdevfs_ioctl command;
int ret;
int fd;
int i;
if (argc>1) {
fd = open(argv[1],O_RDWR);
if (fd<1){
perror("unable to open file");
return 1;
}
for (i=0;i<255;i++){ // hack: should fetch how many interface there is.
command.ifno = i;
command.ioctl_code = USBDEVFS_DISCONNECT;
command.data = NULL;
ret = ioctl(fd, USBDEVFS_IOCTL, &command);
if(ret!=-1)
printf("un claimed interface %d %d\n",i,ret);
}
} else {
printf ("usage: %s /dev/bus/usb/BUS/DEVICE\n",argv[0]);
printf("Release all interfaces of this usb device for usage in virtualisation\n");
}
}

File diff suppressed because it is too large Load Diff