2

PCEngines – APU Board and nct5104d gpio driver

The board 🙂

Today I will explain you how I managed to write my own custom driver for nct5104d under Centos running on PCEngines APU board . But before we go any further wanted to share my “big wow” to the makers of the board. For anyone doing home automation , tinkering around or being just interested in engineering it is something I can completely recommend. It features amongst many cool perks things like 3 Gig ethernet ports , 16(18) GPIO ports , I2C , 2xRS232 ( one with RX,TX only ). For me its 5/5 start rating 🙂

 

In a place far far away…

… I have started this post some time ago since I thought it would be a great idea to have opportunity of sharing my experience as I  go through the whole learning of how to write a Linux driver for nct5104d  ( sitting on APU board )

Before I decided to anything crazy like that I would like to let you know that there is already a driver for the device and you can find it https://github.com/tasanakorn/linux-gpio-nct5104d . What made me thinking of writing my version was the way I would need to interoperate with the GPIOs by making some funky commands like :

echo 1 > /sys/class/gpio/gpio0/value

At that moment I knew I can make it easier for my automation purposes 🙂

 

Writing own driver …  where to start ?

So this is good question to ask yourself here. It took me many hours of reading articles/forums but also talking with people that have been doing such things before. From a high level perspective its simple – read basics and then start small with hello world. Once you start understanding it you will have more results.

I could recommend you take a look at the following resources ( which I have found very useful for getting my head around 🙂  )

 

Step by step ?

 

In most of my articles we would probably dive into technical details of the challenge. But in this instance I will point you to my github repository and ask to take a look. There has been a big amount of work that I have put into this and if you will have specific questions I will be here to try and answer them!

 

As just as interesting part – thats how my work looked like though the last 2 weeks ( from start to finish 🙂 )

Where is the code ?

 
The complete repository is available in my github repo https://github.com/RafPe/gpio-driver-nct5104d

 

So how does it work ?

Now we are talking 🙂 So using the driver is really nice. Once you go through the steps of compiling it and installing in your system you then have access to device via ioctl.

I have exposed methods for interacting with registries and with pins. However what is important here – the device automatically uses Logical device 7 which is GPIO. If you would have other needs we would most likely need to compile some logic around it.

Since not everyone is guru in creating binaries 🙂 I have created 2 apps which are respectively for management of pins or registries

 

Managing pins

With simple commands you can manage pins instantly

nct5104dpin [ --get|--set ] [--pin ] --val < 0|1 > --dir <out|in>

Get a pin value: nct5104dpin --pin 7 
Get a pin value: nct5104dpin --get --pin 14
Set a pin value: nct5104dpin --set --pin 14 --val 1
Set a pin direction: nct5104dpin --set --pin 14 --dir out

Cool thing is that I have made it in such a way that parsing data with i.e. JQ is just straightforward.

[email protected] > nct5104dpin --pin 1 | jq
[
  {
    "pin": 1,
    "value": 0
  }
]

Managing registries

Same apply for managing registers. I have been aiming to keep it simple and specific.

ct5104dreg [ --get|--set ] [--reg ] <HEX> --val <DECIMAL> 

Get a reg value: nct5104dreg --reg 0x07 
Get a reg value: nct5104dreg --get --reg 0x07
Set a reg value: nct5104dreg --set --reg 0xE0 --val 252

Here I also made sure output can easily be parsed

[email protected] > nct5104dreg --reg 0xE1 | jq
[
  {
    "registry": "0xe1",
    "value": 248
  }
]

 

Adventure begins here

I hope by sharing this I will enable you or maybe someone else to do things that you have not been doing before 🙂 or at least get you interested

 

0

STM32 Adventures – Communication using I2C


When working with STM32 using registries only it is important that you have REFERENCE MANUAL and DATASHEET available. We will use them a lot 🙂


 

Today we start with I2C communication protocol. Configuration of it might be a bit of tricky at the beginning gut I hope to explain to you what I have came across of when trying to get the protocol to work. For more details about I2C itself check out wiki .

Device address

Since I have worked with it I usually like to start off with defining address of the device that I’m working with ( or devices if you work with more than one ).

#define DEVICE_ADDRESS 0x01
#define DEVICE_ADDRESS_W (DEVICE_ADDRESS << 1)
#define DEVICE_ADDRESS_R (DEVICE_ADDRESS_W | 1)

This has saved me many times from problems with wrong addressing and spending time troubleshooting something which is easy as above 🙂

Transmission flow

So now its time to dive back into RM. We need to find part about I2C. Since we will be building a master device we focus there (at least for now ). As you can see on image below its shows really nice what we must program. Specific events at specific point of transmissions ( for transmitter and receiver ). This makes it really easy to code against.

RMf407vgen_DM00031020_i2c_01

 

Configuration of peripherial

Let’s move on to configuration. What is important for you is to know that the code presented here is not using interrupts or DMA. Reason for this is slow build up of skills. I will document those later on and update the links in this post accordingly.

Let’s start by finding which PINs we need to configure. For that one I jump to DS and search for I2C1 (that one I want to use ) and checkout Alternate Function Mappings

DSF407VGen_DM00037051_af_i2c

 

So now I can choose even what suits me more 🙂 I will stick with PB6 and PB7. Below function will set those pins as alternate function, high speed , open drain and finally configure that we use AF4 for those pins.

/*
 * Function responsbile for configuration
 * of GPIO pins
 */
void i2c_setup_gpio(void)
{
	GPIOB->MODER |= GPIO_MODER_MODER6_1 |   // AF: PB6 => I2C1_SCL
			GPIO_MODER_MODER7_1; 	// AF: PB7 => I2C1_SDA


	GPIOB->OTYPER |= GPIO_OTYPER_OT_6|
			 GPIO_OTYPER_OT_7;

	GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6|
			  GPIO_OSPEEDER_OSPEEDR7;

	GPIOB->PUPDR |= GPIO_PUPDR_PUPDR6_0|
			GPIO_PUPDR_PUPDR7_0;

	/*
	 * Alternate functions are configured in ARFL for PINS 0..7
	 * and in ARFH for PINS 8..15
	 * Based on DS we will select appropiate AF0..AF7
	 */
	GPIOB->AFR[0] |= ( 1 << 30 ) | ( 1 << 26); // P6/P7 => AF4
}

If you have by any chance forgotten about RCC here is my routine which I used to enable all peripherals

void rcc_init(void)
{

	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN|	// Enable clock: GPIOB
			RCC_AHB1ENR_GPIOCEN;	// Enable clock: GPIOC
	RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;	// Enable clock: I2C1

	__DSB();	// Data Synchronization Barrier

}

Once hardware is ready we can configure the I2C registries.

void i2c_init(void)
{

	/*
	 *  Reset I2C from lock state
	 */
	//I2C1->CR1 |= I2C_CR1_SWRST;

	/*
	 * FREQ: Set frequencey based on APB1 clock
	 * 8MHz
	 */
	I2C1->CR2 &= ~(I2C_CR2_FREQ);
	I2C1->CR2 |= 0x08;

	/*
	 * Depending on the frequency of said prescaler must be installed in
	 * accordance with the selected data rate.
	 * We choose the maximum, for standard mode - 100 kHz:
	 *
	 *  8MHz / 100 = 80 kHz;
	 *
	 */
	I2C1->CCR &= ~I2C_CCR_CCR;
	I2C1->CCR |= 80;

	/*
	 * clock period is equal to (1 / 8 MHz = 125 ns), therefore the maximum rise time:
	 * 1000 ns / 125 ns = 8 + 1 (plus one - a small margin) = 3
	 *
	 */
	I2C1->TRISE = 9;


	/*
	 * Enable perifpherial at the END
	 */
	I2C1->CR1 = I2C_CR1_ACK|
	I2C_CR1_PE;     // PE : Peripherial enable
}

Its quite easy here – we set freq of peripherial ( in my case it was 8Mhz ) then set clock rate ( which has simple formula ) and then we setup time rise. All of this is documented in RM and clearly explained.

The only thing that is left now is to read and write from the device.

Read using I2C

uint8_t i2c_read(uint8_t address, uint8_t registry)
{
	uint32_t timeout = TIMEOUT_MAX;

	while(I2C1->SR2 & I2C_SR2_BUSY);		// Wait for BUSY line
	I2C1->CR1 |= I2C_CR1_START;				// Generate START condition

	while (!(I2C1->SR1 & I2C_SR1_SB)); 		// Wait for EV5
	I2C1->DR = address<<1;					// Write device address (W)

	while (!(I2C1->SR1 & I2C_SR1_ADDR));	// Wait for EV6
    (void)I2C1->SR2;						// Read SR2

	while (!(I2C1->SR1 & I2C_SR1_TXE));		// Wait for EV8_1
	I2C1->DR = registry;

	I2C1->CR1 |= I2C_CR1_STOP;				// Generate STOP condition


	I2C1->CR1 |= I2C_CR1_START;				// Generate START condition

	while (!(I2C1->SR1 & I2C_SR1_SB)); 		// Wait for EV5
	I2C1->DR = (address << 1 ) | 1;			// Write device address (R)

	while (!(I2C1->SR1 & I2C_SR1_ADDR));	// Wait for EV6
    I2C1->CR1 &= ~I2C_CR1_ACK;              // No ACK
    (void)I2C1->SR2;						// Read SR2

	while (!(I2C1->SR1 & I2C_SR1_RXNE));	// Wait for EV7_1
    uint8_t value = (uint8_t)I2C1->DR;      // Read value

    I2C1->CR1 |= I2C_CR1_STOP;			    // Generate STOP condition

	return value;
}

Writing using I2C

void i2c_write(uint8_t address, uint8_t registry, uint8_t data) 
{


	I2C1->CR1 |= I2C_CR1_START;				// Generate START condition

	while (!(I2C1->SR1 & I2C_SR1_SB)); 		// Wait for EV5
	I2C1->DR = address<<1;					// Write device address (W)

	while (!(I2C1->SR1 & I2C_SR1_ADDR));	// Wait for EV6
    reg2 = I2C1->SR2;						// Read SR2

	while (!(I2C1->SR1 & I2C_SR1_TXE));		// Wait for EV8_1
	I2C1->DR = registry;					// Write registry address

	while (!(I2C1->SR1 & I2C_SR1_BTF));	    // Wait for BTF
	I2C1->DR = data;

	I2C1->CR1 |= I2C_CR1_STOP;			    // Generate STOP condition
}

Summary

Code presented above has still work in progress as I need to add error control and timeouts – otherwise if something would go wrong now it would block whole uC

 


logo_github

 

Code for this exercise can be of course found at github https://github.com/RafPe/STM32F4DISCOVERY-I2C

 

 

 


 

 

 

 

 

 

 

 

0

STM32 Adventures – output clock to pin


When working with STM32 using registries only it is important that you have REFERENCE MANUAL and DATASHEET available. We will use them a lot 🙂


 

In today’s post we will be outputting SYSCLK to external pin of our STM32F407 discovery board. As mentioned we dive into our RM and find part responsible for RCC configurations. From there it is easy to see which bits we need to output SYSCLK to our pin.

stm32_clockoutput_01

 

As you can see on the above reset value shows that desired SYSCLK and default no prescaler will be selected. Then in this instance let’s find out on which pin we have to enable our alternate function.

To do this we need to find it in DS.

stm32_clockoutput_02

 

Great – it is default system function! So the only thing we should do is just set this PIN as output

int main(void)
{

	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;	// Enable clock: GPIOC

	/*
	 *  Enable SYSCLK output to PC9
	 */
	GPIOC->MODER |= GPIO_MODER_MODER9_1 ;   // AF: PC9 => MCO2
}

 

let’s see it if works by looking into our logic level analyzer

stm32_clockoutput_03

 

We will defenitely be able to use this functionality in interacting with external hardware – but thats for future posts

0

Flashing ESP8266 ESP-03 with NodeMCU

Recently I have been working with ESP8266 ESP-03 and decided to flash it with NodeMCU. Looking at how to do this ( here ) it seemed to be pretty straight. forward task.

However when I started to try and flash the module I have not received any results. Most of the cases module became unresponsive. After many hours ( really ) of looking for some guideline where the problem can be I have came across post which referenced to write the default data into 2 memory addresses of the module.

So I have done so with the following command and that has helped – now got my nodemcu running as it should be!

 

esptool.py --port /dev/tty.usbserial-A7HFE6HK --baud 115200 write_flash -fm qio -fs 4m 0x00000 bin/nodemcu_integer_master_20161025-0533.bin 0x7C000 ~/Downloads/esp8266_nonos_sdk_v2.0.0_16_08_10/ESP8266_NONOS_SDK/bin/esp_init_data_default.bin 0x3fc000 ~/Downloads/esp8266_nonos_sdk_v2.0.0_16_08_10/ESP8266_NONOS_SDK/bin/esp_init_data_default.bin

Hope this will help you if you have been looking for some tips!

 

0

STM32 – minimal libraries project

Hey! So you most likely here because you would like to challenge yourself and try to program 32bit microcontrollers using minimal amount of libraries ( HAL/CMSIS ). On the internet you will find multiple discussions which approach to use – I will not be touching that – I guess everyone has his own way 😉

We will starting by shortly discussing environment used and then we will move on to configuring our project. I will be using for this STM324F407 discovery board – but with the right changes you will be able to adjust it to your own needs.

I will cover in this post:

  • Creating new project in Eclipse
  • Setting all libraries
  • Setting project & compilator settings

Before you start you should have

 

This project will use several files i.e. startup file / linker script and several header files.

 

Setting up project

Go ahead and create new ARM project. Here we will not be using any ‘Hello world’ or prepared examples – we start blank!

stm32_minimallibs_01

 

Here just go through the wizard and finish. When done we will move on getting extra files we need for our project.

 

Create folders inside the project folder so the structure will look as follow

stm32_minimallibs_02

Download firmware using STM32Cube

Now we need to start our STM32Cube to get all files we will need to move on with our project. Go to help -> install new libraries and then select the firmware for your cortex. For me it will be for STM32F4

stm32_minimallibs_04

 

Get following files into the project directories:

├── cmsis
│   ├── include
│   │   ├── cmsis_gcc.h
│   │   ├── core_cm0plus.h
│   │   ├── core_cm4.h ** THIS IS BASED ON YOUR CORTEX!! If you have different take different lib file !! **
│   │   ├── core_cmFunc.h
│   │   ├── core_cmInstr.h
│   │   └── core_cmSimd.h
│   └── src
├── include
├── src
│   └── main.c ( this is file created by you )
└── system
    ├── include
    │   ├── stm32f407xx.h
    │   ├── stm32f4xx.h
    │   └── system_stm32f4xx.h
    └── src
        ├── startup_stm32f407xx.s
        └── system_stm32f4xx.c

 

Modify project settings

Now since we have all the files we need your project should look similar to the following

stm32_minimallibs_05

 

We will now go and modify several project settings. Open project preferences and make required modifications

  • Change extension used by assembler source file to be *.s ( it’s project specific setting )stm32_minimallibs_06
  • Change to appropriate cortex family modelstm32_minimallibs_07
  • Modify preprocessor definitions to match your processor ( this settings in image below are for STM32F407VGx )stm32_minimallibs_08
  • Modify includes in Assembler and Compiler so it contains “${ProjDirPath}/cmsis/include” and “${ProjDirPath}/system/include
  • Under Linker -> General have the following ${ProjDirPath}/STM32F407VGTx_FLASH.ld ( if you are using different MCU then you will need to change this )
  • Modify paths which include source codestm32_minimallibs_09

 

Blink the diode

So now you are in position to just blink the diode using the following code in main.c

/*
 * main.c
 *
 *  Created on: 12 Nov 2016
 *      Author: rafpe
 */
#include "stm32f4xx.h"
#include "stm32f407xx.h"




int main(void)
{
	volatile uint32_t delay;

	RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD

	__DSB();

	GPIOD->MODER = (1 << 26); // set pin 13 to be general purpose output

	while (1)
	{
		for (delay = 1000000; delay; delay--)
		{
			GPIOD->ODR ^= (1 << 13);
		}
	}
}

 

Compile and you are ready to flash your device.

 

 

Caveouts

Given all setup here we are HSI is used as system clock source. We will definitely come back to this as we will need more than i.e. 16 Mhz! Happy coding!

 

 

 

 

1

Using STM32CubeMX on MacOS

When it comes to using multiple tools to program/develop it can be sometimes challenging to have them running in single OS. Might be that you would end up having virtual machine running some of your tools – which of course – does not make it easier at all!

One of tools that I really have need of using ( when it comes to development of 32bit microcontrollers ) is STM32CubeMX. If you have not clue what that tool does – in short – it is GUI which allows for quick configuration of microcontroller and its peripheral. It is nice at the end to generate you the code in selected IDE project format ( we will come back to alternate use of this in one of next posts )

Download the software

We will start off with downloading the software. Go STM32CubeMx download page  and scroll down to the bottom. You will find the download option for the software there

stm32cubemx_-_stm32cube_initialization_code_generator_-_stmicroelectronics_-_stmicroelectronics

 

Page requires you to create account – but that is part which I leave completely up to you 😉

 

Install software

Once downloaded on our Mac it would be great to just go ahead and install. If you open folder you will see the following files.

cubemx_downloaded_folder

 

For obvious reasons you will start the ‘application’ file which in return will open the installer

stm32cubemx_installation_wizard__and_downloads

 

The installation is like ‘camera’ – just next => next=> done! The only thing you need to do now is to open it and use it features!

 

Use the app

new_project_and_stm32cubemx_untitled_and_edit_post__automation_ninja_s_dojo_-_wordpress

 

I hope this will get you and your toolkit on the right track! Enjoy coding!

 

 

 

0

Setup for AVR development on MacOS

Hey,

So today we look into something which I really was looking for recently. In nutshell it is setup of required components which are necessary to program AVRs on our MacOS.

Here I assume you for sure already have HomeBrew installed as it will be our main point of software installation.

 

Add new tap

brew tap osx-cross/avr

Install avr-gcc

brew install avr-libc

This one will install avr-binutils and avr-gcc. The avr-gcc installation takes time as it is compiling … so make ur self your favourite drink here 😉

 

Install avrdude

brew install avrdude --with-usb

 

Avrdude error when loading MCU in Eclipse

If you have error when using Eclipse and avrdude it seems that the AVR plugin has not been updated for a while. Although this does not affect programming can be easily solved. My friend sanderv32 has created a really nice AVRdude wrapper which solves this problem once and for all!

You can find his repo here => https://github.com/sanderv32/avrdude-av

 

Happy coding!

0

AVR Library for WS2803 LED Driver IC

ledySo today I will be sharing with you one of my maybe not so recent but reliable libraries. It is for WS2803 which I think is really cool IC that allows you to control outputs with PWM using SPI to control data being sent.

 

The amount of components needed is really minimal as we only need to provide one single reference resistor which will limit the amount of current for our outputs.

 

One thing you could ask is how do you connect to it without a lot of hustle ? Well I personally for my electronical challenges use ATB Development boards manufactured by Atnel.pl. Reason for this specific set ? Well first of all it is extremely high quality packed with all items which you would even imagine you could need 😀 Take a look …

 

What you see here below is previous version and the newest and shiniest version of ATB devboard.
2016-06-25 225703

2016-06-25 225650

 

Packed like this I’m ready to challenge the WS2803 … I won’t be providing connection schematics as internet and datasheet are available all over the internet.

Library is available under here and you can just go ahead and download it. Since I have been developing this on AVR Atmega32 it is using hardware SPI defined in SPI library.

The only pins you need there is MOSI and CLK. This is all needed to drive WS2803. Since there is no magic in sending data using SPI protocol let’s dive into WS803 library.

Before you begin I think you should now that I have written my own implementation of delay function. Reason for that is in this version I haven’t used interrupts and needed to be able to control delays with variables.

static inline void delay_ms(uint16_t count) 
{
  while(count--) 
  {
      delay_ms(1);
  }
}

Once you add library files to you project you will need to first define yourself buffer. I have tendency of defining how many outputs I will have and using that definition in the rest of my program.

So you could do the following to start …

define WS2803_LED_CNT 18 

uint8_t ws_buf[ WS2803_LED_CNT ];
uint8_t * ptrBuf = ws_buf;

 

Now we are ready to start fun…. easiest is to try and light out all of LEDs ( outputs ). For this we will use function which operating on memory sets all values in our buffer to single value

ws2803_set_all( ptrBuf , 255);    
ws2803_shift_out( ptrBuf ); 
delay_ms(3000);

Easy 🙂 Well – most up to date is always the github and there you will be able to find remaining functions and some examples i.e.

  • Fade in
  • Fade out
  • Draw line
  • Light up one by one

RafPe_WS2803__Repository_with_library_designed_to_drive_ws2803_from_AVR

0

CNC your custom usb slide-in PCB

So I had troubles properly naming title of this post. So as a short explanation my passion also includes electronics 🙂 and today I felt like playing with USB and RS232 ( reason for that will be obvious in one of later posts ).

Now in order to get this working I could most probably just get USB port and solder some cables into it but I think this would totally miss the idea of fun – especially in my case.

So where do we start ? We need to make a design ? No problemos 🙂 using Eagle CAD I have created board schematic ( as in my case schematic for electronics is not needed 🙂 )

The final design after a moment looked like this :

usbslider_01

 

So that was the easy part right ? Well yes 🙂 However I do not forget that “sharing is caring” thats why you can download the project here

 

Ok so how do we get our project from digital world to our matrix 🙂 ? There are several available methods :

  • Chemical etching
  • UV
  • CNC
  • Order your PCB at professional services

 

In my experience I have already been through chemical etching and though it works nice – yeah….. at certain point you get tired of all that action you need to execute . UV I have not yet played with ( but it also includes chemical toys ). Professional services is also not an option as this project is so small and I need it kinda … now 🙂 so we are left with cool one …. CNC

2016-06-21 231039

 

 

Now with help of a bit of machine software and some PCB material I got the board ready in like 7 minutes. Machine is capable of faster operations but with PCB I would be risking damage to reallllyyyyy small drill bits ( talking from expensive experience here 🙁 ) so thats perfectly fine with me. After machine was done I was presented with the following view 🙂

IMG-20160620-WA0003

 

hey ya! That is what I wanted 🙂 However for next version I will need to ditch that outline margin as it was nice enough to connect all points of my board which for USB is not so good !

From there only a bit of soldering and some hot tube to isolate remains and we got this :

 

2016-06-21 221342

2016-06-21 222812

 

As it may not look sooooo super PRO 🙂 but this is a POC prototype to make sure when I need more and order from professional services I get exactly what I expect.

 

If you are using CNC for PCB – leave a comment – interested in your approach