Speech Recognition: CMUSphinx + Raspberry Pi

Beberapa waktu lalu saya penasaran dengan aplikasi speech recognition. Setelah bertanya pada teman saya disarankan untuk menggunakan engine dari CMUSphix. Kelengkapan alatnya adalah raspberry pi + usb microphone + 2 buah LED sebagai device yang akan kita kontrol menggunakan suara.

Langsung saja kita install aplikasi yang dibutuhkan oleh raspbian. Silahkan buka link berikut
https://wolfpaulus.com/embedded/raspberrypi2-sr/
atau jalankan satu-persatu command di bawah ini.

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install bison
sudo apt-get install libasound2-dev
sudo apt-get install swig
sudo apt-get install python-dev
sudo apt-get install mplayer
sudo reboot

lalu mari kita cek apakah microphone dan speaker bekerja dengan baik.

arecord -D plughw:0,0 -f cd ./test.wav

gunakan ctrl+c untuk berhenti merekam. Lalu mainkan hasil rekaman kita.

aplay ./test.wav

setelah itu, kita install sphinxbase.

cd ~/
wget http://sourceforge.net/projects/cmusphinx/files/sphinxbase/5prealpha/sphinxbase-5prealpha.tar.gz
tar -zxvf ./sphinxbase-5prealpha.tar.gz
cd ./sphinxbase-5prealpha
./configure --enable-fixed
make clean all
make check
sudo make install

setelah itu, install pocketsphinx

cd ~/
wget http://sourceforge.net/projects/cmusphinx/files/pocketsphinx/5prealpha/pocketsphinx-5prealpha.tar.gz
tar -zxvf pocketsphinx-5prealpha.tar.gz
cd ./pocketsphinx-5prealpha
./configure
make clean all
make check
sudo make install

Kemudian mari kita buat language model dan dictionary yang berformat .lm dan .dic
Buatlah sebuah text file kemudian isikan kata-kata yang akan dikenali oleh raspbery pi.

Hello Pixel
Red On
Red Off
Blue On
Blue Off
All On
All Off
Shutdown Now

save file tersebut dan berinama apa saja. Lalu buka link berikut. http://www.speech.cs.cmu.edu/tools/lmtool-new.html untuk meng-generate .lm dan .dic

Download .lm dan .dic, lalu buat direktori project kita. Misal saya gunakan nama folder MySphinx di directory /home/pi/MySphinx.

Setelah itu buka console kembali dan kita test pocketsphinx dan language model yang sudah kita generate. Jangan lupa ketikan nama .lm dan .dic yang telah kita donwload tadi mempunyai nama yang sama dengan command berikut dan kode di bawah nanti.

cd ~/
export LD_LIBRARY_PATH=/usr/local/lib
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
pocketsphinx_continuous -hmm /usr/local/share/pocketsphinx/model/en-us/en-us -lm /home/pi/MySphinx/4979.lm -dict /home/pi/MySphinx/4979.dic -samprate 16000/8000/48000 -inmic yes –adcdev plughw:1,0

-adcdev plughw:1,0 merupakan perintah untuk memilih device ID dari microphone. Cek dengan command

cat /proc/asound/cards

Hasilnya adalah.

0 [ALSA ]: bcm2835 - bcm2835 ALSA
bcm2835 ALSA
1 [AK5370 ]: USB-Audio - AK5370
AKM AK5370 at usb-bcm2708_usb-1.2, full speed

Setelah pocketsphinx berhasil maka mari kita buat custom project kita sendiri. Skenarionya adalah, ketika program dijalankan maka akan memainkan musik piano, lalu raspberry pi akan mengucapkan hello sir. Kemudian barulah raspbery pi memulai voice recognition dan akan menjalankan perintah yang kita berikan, yaitu menghidupkan/mematikan LED dan auto shutdown.
Buka console kembali. Kita install terlebih dahulu espeak.

sudo apt-get install espeak

untuk mengetesnya ketik command.

espeak "hello"

maka dari raspberry pi akan keluar suara hello.
Setelah itu, kita donwload file piano.wav yang akan kita gunakan sebagai musik pembuka.

cd /home/pi/MySphinx
wget http://www.kozco.com/tech/piano2.wav

setelah itu, kita coba cek mainkan file tersebut dengan ketikan.

aplay piano2.wav

Kemudian, setelah file dan aplikasi yang kita butuhkan sudah lengkap. Kita buat file test3.c lalu masukan kode berikut.

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

#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
#else
#include <sys/select.h>
#endif

#include <sphinxbase/err.h>
#include <sphinxbase/ad.h>

#include "pocketsphinx.h"

#define LED_RED	21
#define LED_BLUE	22

static ps_decoder_t *ps;
static cmd_ln_t *config;

/* Sleep for specified msec */
static void
sleep_msec(int32 ms)
{
#if (defined(_WIN32) && !defined(GNUWINCE)) || defined(_WIN32_WCE)
    Sleep(ms);
#else
    /* ------------------- Unix ------------------ */
    struct timeval tmo;

    tmo.tv_sec = 0;
    tmo.tv_usec = ms * 1000;

    select(0, NULL, NULL, NULL, &tmo);
#endif
}

/*
 * Main utterance processing loop:
 *     for (;;) {
 *        start utterance and wait for speech to process
 *        decoding till end-of-utterance silence will be detected
 *        print utterance result;
 *     }
 */
static void
recognize_from_microphone()
{
    ad_rec_t *ad;
    int16 adbuf[2048];
    uint8 utt_started, in_speech;
    int32 k;
    char const *hyp;

    if ((ad = ad_open_dev("plughw:0,0",16000)) == NULL)
        E_FATAL("Failed to open audio device\n");
    if (ad_start_rec(ad) < 0)
        E_FATAL("Failed to start recording\n");

    if (ps_start_utt(ps) < 0)
        E_FATAL("Failed to start utterance\n");
    utt_started = FALSE;
    E_INFO("Ready....\n");

    for (;;) {
        if ((k = ad_read(ad, adbuf, 2048)) < 0)
            E_FATAL("Failed to read audio\n");
        ps_process_raw(ps, adbuf, k, FALSE, FALSE);
        in_speech = ps_get_in_speech(ps);
        if (in_speech && !utt_started) {
            utt_started = TRUE;
            E_INFO("Listening...\n");
        }
        if (!in_speech && utt_started) {
            /* speech -> silence transition, time to start new utterance  */
            ps_end_utt(ps);
            hyp = ps_get_hyp(ps, NULL );
            if (hyp != NULL) {
		if(	strcmp(hyp,"HELLO PIXEL") == 0)
		{
			system("espeak 'hello, what can i do for you, sir'");
			printf("%s\n", hyp);
		}else if(strcmp(hyp,"RED ON") == 0)
		{
			system("espeak 'red, on'");
			printf("%s\n", hyp);
			digitalWrite(LED_RED , HIGH);
		}else if(strcmp(hyp,"RED OFF") == 0)
		{
			system("espeak 'red, off'");
			printf("%s\n", hyp);
			digitalWrite(LED_RED , OFF);
		}else if(strcmp(hyp,"BLUE ON") == 0)
		{
			system("espeak 'blue, on'");
			printf("%s\n", hyp);
			digitalWrite(LED_BLUE , HIGH);
		}else if(strcmp(hyp,"BLUE OFF") == 0)
		{
			system("espeak 'blue, off'");
			printf("%s\n", hyp);
			digitalWrite(LED_BLUE , OFF);
		}else if(strcmp(hyp,"ALL ON") == 0)
		{
			system("espeak 'all, on'");
			printf("%s\n", hyp);
			digitalWrite(LED_RED ,  HIGH);
			digitalWrite(LED_BLUE , HIGH);
		}else if(strcmp(hyp,"ALL OFF") == 0)
		{
			system("espeak 'all, off'");
			printf("%s\n", hyp);
			digitalWrite(LED_RED , LOW);
			digitalWrite(LED_BLUE , LOW);
		}else if(strcmp(hyp,"SHUTDOWN NOW") == 0)
		{
			printf("%s\n", hyp);
			system("aplay -D plughw:CARD=ALSA /home/pi/MySphinx/piano2.wav && shutdown now");
		}else
		{
			printf("Thinking....%s\n", hyp);
		}
                fflush(stdout);
            }

            if (ps_start_utt(ps) < 0)
                E_FATAL("Failed to start utterance\n");
            utt_started = FALSE;
            E_INFO("Ready....\n");
        }
        sleep_msec(100);
    }
    ad_close(ad);
}

int
main(int argc, char *argv[])
{
    char const *cfg;

    config = cmd_ln_init(	NULL, ps_args(), TRUE,
				"-hmm", "/usr/local/share/pocketsphinx/model/en-us/en-us",
				"-lm",  "/home/pi/MySphinx/4979.lm",
				"-dict","/home/pi/MySphinx/4979.dic",
				"-samprate","16000/8000/48000",
				NULL);

    if(config == NULL){
	fprintf(stderr, "Failed to create object, see long for details\n");
	return -1;
    }

    ps = ps_init(config);
    if (ps == NULL) {
        fprintf(stderr, "Failed to create recognizer, see long for details\n");
	return -1;
    }

    E_INFO("%s COMPILED ON: %s, AT: %s\n\n", argv[0], __DATE__, __TIME__);
    
	wiringPiSetupGpio();
	pinMode(LED_RED,  OUTPUT);
	pinMode(LED_BLUE, OUTPUT);
	
    system("aplay -D plughw:CARD=ALSA /home/pi/MySphinx/piano2.wav && espeak 'Hello, Sir!' ");
	
	digitalWrite(LED_RED , HIGH);
	digitalWrite(LED_BLUE, HIGH);
	delay(500);
	digitalWrite(LED_RED , LOW);
	digitalWrite(LED_BLUE, LOW);
	
    recognize_from_microphone();
    
    ps_free(ps);
    cmd_ln_free_r(config);

    return 0;
}

Setelah itu kita kembali ke console terminal dan compile test3.c yang sudah kita buat. Kita masuk dulu ke directory MySphinx

cd /home/pi/MySphinx
gcc -o test3 test3.c -DMODELDIR=\"`pkg-config --variable=modeldir pocketsphinx`\" `pkg-config --cflags --libs pocketsphinx sphinxbase` -lwiringPi

Setelah itu kita jalankan dengan

sudo ./test3

Selesai.
Jika ingin dijalankan autorun maka tambahkan

sudo /home/pi/MySphinx/test3

di bagian terakhir dari /home/pi/.bashrc. Buka file tersebut dengan command

sudo nano /home/pi/.bashrc

agar raspberry pi dijalankan tanpa Desktop GUI lakukan pengaturan dengan command

sudo raspi-config

_______________________________________________________________________
referensi:
https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=126436
https://wolfpaulus.com/embedded/raspberrypi2-sr/
http://www.penguintutor.com/linux/rpi-pixel-virtualbox
https://www.raspberrypi.org/forums/viewtopic.php?t=85627&p=604943
https://www.dexterindustries.com/howto/run-a-program-on-your-raspberry-pi-at-startup/
http://people.csail.mit.edu/hubert/pyaudio/#downloads
http://blog.justsophie.com/python-speech-to-text-with-pocketsphinx/
http://depado.markdownblog.com/2015-05-13-tutorial-on-pocketsphinx-with-python-3-4
https://cmusphinx.github.io/wiki/tutorialpocketsphinx/
https://www.dexterindustries.com/howto/make-your-raspberry-pi-speak/
https://www.howtogeek.com/269509/how-to-run-two-or-more-terminal-commands-at-once-in-linux/
http://mailman.alsa-project.org/pipermail/alsa-devel/2014-May/077142.html
https://www.raspberrypi.org/forums/viewtopic.php?f=66&t=95724
youtube.com/watch?v=J6KsTz6hjfU

STM32F4 Discovery + STM32CubeMX + Keil: RTOS

Biasanya RTOS dipakai ketika aplikasi yang dibuat sudah mulai kompleks. Akan tetapi, pada postingan ini saya hanya mencoba dengan aplikasi push button dan led saja. Skenarionya adalah membuat 4 task.
Task 1 Fast blinking LED1 dengan delay 300ms
Task2 Slow blinking LED2 dengan delay 3000ms
Task3 read push button
Task4 merespon push button dengan LED3 dan LED4.
Buka STM32CubeMX dan buat New Project. Atur Pin configuration.

Enable FreeRTOS.

Pada tab configuration klik FreeRTOS

Buat task baru sebagai berikut.

Setelah itu klik generate source code. Berinama project dan setting toolchain MDK-ARM V5 lalu Klik OK dan Open Project. Buka main.c
Tambahkan variable counter dan statusLED sebagai berikut.

Lalu pada task yang sudah dibuat, kita tambahkan kode berikut.

Build project dan download program.
Berikut full code main.c

/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"
#include "cmsis_os.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
osThreadId defaultTaskHandle;
osThreadId fastLEDHandle;
osThreadId slowLEDHandle;
osThreadId pushButtonHandle;
osThreadId restLEDHandle;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t counter = 0;
GPIO_PinState statusLED;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
void StartDefaultTask(void const * argument);
void StartFastLED(void const * argument);
void StartSlowLED(void const * argument);
void StartPushButton(void const * argument);
void StartRestLED(void const * argument);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* definition and creation of fastLED */
  osThreadDef(fastLED, StartFastLED, osPriorityNormal, 0, 128);
  fastLEDHandle = osThreadCreate(osThread(fastLED), NULL);

  /* definition and creation of slowLED */
  osThreadDef(slowLED, StartSlowLED, osPriorityNormal, 0, 128);
  slowLEDHandle = osThreadCreate(osThread(slowLED), NULL);

  /* definition and creation of pushButton */
  osThreadDef(pushButton, StartPushButton, osPriorityNormal, 0, 128);
  pushButtonHandle = osThreadCreate(osThread(pushButton), NULL);

  /* definition and creation of restLED */
  osThreadDef(restLED, StartRestLED, osPriorityNormal, 0, 128);
  restLEDHandle = osThreadCreate(osThread(restLED), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */
 

  /* Start scheduler */
  osKernelStart();
  
  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0);
}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PD12 PD13 PD14 PD15 */
  GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/* StartDefaultTask function */
void StartDefaultTask(void const * argument)
{

  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END 5 */ 
}

/* StartFastLED function */
void StartFastLED(void const * argument)
{
  /* USER CODE BEGIN StartFastLED */
  /* Infinite loop */
  for(;;)
  {
	HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
    osDelay(300);
  }
  /* USER CODE END StartFastLED */
}

/* StartSlowLED function */
void StartSlowLED(void const * argument)
{
  /* USER CODE BEGIN StartSlowLED */
  /* Infinite loop */
  for(;;)
  {
    HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_13);
	osDelay(3000);
  }
  /* USER CODE END StartSlowLED */
}

/* StartPushButton function */
void StartPushButton(void const * argument)
{
  /* USER CODE BEGIN StartPushButton */
  /* Infinite loop */
  for(;;)
  {
	if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0))
	{
		while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0));
		counter++;
	}
    osDelay(1);
  }
  /* USER CODE END StartPushButton */
}

/* StartRestLED function */
void StartRestLED(void const * argument)
{
  /* USER CODE BEGIN StartRestLED */
  /* Infinite loop */
  for(;;)
  {
	if(counter == 0)
	{
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
	}
	else if(counter == 1)
	{
		HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_14);
		HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_15);
		HAL_Delay(1000);
	}
	else if(counter == 2)
	{
		statusLED = ~statusLED;
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, ~statusLED);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, statusLED);
		HAL_Delay(500);
	}
	else 
	{
		counter = 0;
	}
    osDelay(1);
  }
  /* USER CODE END StartRestLED */
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler */ 
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/**
  * @}
  */ 

/**
  * @}
*/ 

STM32F4 Discovery + STM32CubeMX + Keil: Accelerometer

Pada kesempatan kali ini kita akan memcoba mengakses data dari sensor accelerometer dengan koneksi SPI dan menampilkan hasil pengukuran pada LED.


Berikut alamat register dari LIS3DSH, sensor accelerometer yang terdapat pada STM32F4 Discovery.

Buka aplikasi STM32CubeMX. Lalu buat New Project

Pilih tipe mikrokontroller sesuai dengan tipe STM32F4 Discovery yaitu STM32F407VG

Lakukan setting pada pin yang akan kita gunakan.

Pada tab configuration lakukan pengaturan sebagai berikut.

Setelah itu klik generate source code. Berinama project dan setting toolchain MDK-ARM V5 lalu Klik OK dan Open Project.
Buka main.c

int main(void)
{

  /* USER CODE BEGIN 1 */
	uint8_t address, data, x_accel, y_accel, i;
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();

  /* USER CODE BEGIN 2 */
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
	address = 0x20;
	HAL_SPI_Transmit(&hspi1, &address, 1, 50);
	data = 0x67;
	HAL_SPI_Transmit(&hspi1, &data, 1, 50);
	HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
		
	//Blinking LED sebagai indikator siap untuk read accelerometer
	for(i=0;i<4;i++)
	{
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
		HAL_Delay(500);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
		HAL_Delay(500);
	}
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
		/* USER CODE BEGIN 3 */
	
		//----------------------X AXIS---------------------------
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
		address = 0x29 + 0x80;
		HAL_SPI_Transmit(&hspi1, &address, 1, 50);
		HAL_SPI_Receive(&hspi1, &x_accel, 1, 50);
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
  	if((x_accel > 10)&&(x_accel < 127))
		{
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET);
		}
		else if((x_accel < 245)&&(x_accel > 127))
		{
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET);
		}
		else
		{
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET);
		}
		//---------------------Y AXIS----------------------------
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET);
		address = 0x2B + 0x80;
		HAL_SPI_Transmit(&hspi1, &address, 1, 50);
		HAL_SPI_Receive(&hspi1, &y_accel, 1, 50);
		HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET);
  
		if((y_accel > 10)&&(y_accel < 127))
		{
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_SET);
		}
		else if((y_accel < 245)&&(y_accel > 127))
		{
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_SET);
		}
		else
		{
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_13, GPIO_PIN_RESET);
			HAL_GPIO_WritePin(GPIOD, GPIO_PIN_15, GPIO_PIN_RESET);
		}
  }
  /* USER CODE END 3 */
}

_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + STM32CubeMX + Keil: UART Interrupt

Buka aplikasi STM32CubeMX. Lalu buat New Project

Pilih tipe mikrokontroller sesuai dengan tipe STM32F4 Discovery yaitu STM32F407VG

Lakukan setting pada pin yang akan kita gunakan.

Pada tab Configuration klik USART1 dan lakukan pengaturan sebagai berikut.

Setelah itu aktifkan interrupt uart

Setelah itu klik generate source code. Berinama project dan setting toolchain MDK-ARM V5 lalu Klik OK dan Open Project.
Buka main.c
Pada main.c aktifkan uart dengan perintah enable.

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */
	__HAL_UART_ENABLE_IT(&amp;huart1, UART_IT_RXNE);
	__HAL_UART_ENABLE_IT(&amp;huart1, UART_IT_TC);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
   while (1)
  {
		/* USER CODE END WHILE */

		/* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

Setelah itu kita buat variable global sebagai berikut.

Buka stm32f4xx_it.c untuk mengakses Interrupt Service Routine

Pada file stm32f4xx_it.c buat variable global yang akan diakses dari main.c dengan tambahkan extern.

Pada fungsi dibawah ini ketikan perintah transmit dan receive sebagai berikut.


_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + STM32CubeMX + Keil: UART

Buka aplikasi STM32CubeMX. Lalu buat New Project

Pilih tipe mikrokontroller sesuai dengan tipe STM32F4 Discovery yaitu STM32F407VG

Lakukan setting pada pin yang akan kita gunakan.

Pada tab Configuration klik USART1 dan lakukan pengaturan sebagai berikut.

Setelah itu klik generate source code. Berinama project dan setting toolchain MDK-ARM V5 lalu Klik OK dan Open Project.
Buka main.c

int main(void)
{

  /* USER CODE BEGIN 1 */
	char myDataTx[16] = "hello world!";
  char myDataRx[16];
	/* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  /* USER CODE BEGIN 2 */
	HAL_UART_Transmit(&huart1, (uint8_t *)myDataTx, 16, 50);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		/* USER CODE END WHILE */
		HAL_UART_Receive(&huart1, (uint8_t *)myDataRx, 16, 50);
		/* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

}

_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + STM32CubeMX + Keil: PWM

Buka aplikasi STM32CubeMX. Lalu buat New Project

Pilih tipe mikrokontroller sesuai dengan tipe STM32F4 Discovery yaitu STM32F407VG

Lakukan setting pada pin yang akan kita gunakan.

Kemudian pada tab configuration klik TIM1 dan lakukan pengaturan sebagai berikut.

Setelah itu klik generate source code. Berinama project dan setting toolchain MDK-ARM V5 lalu Klik OK dan Open Project.
Buka main.c

int main(void)
{

  /* USER CODE BEGIN 1 */
	uint16_t 	dutyCycle1 = 10, 
						dutyCycle2 = 90, 
						dutyCycle3 = 10, 
						dutyCycle4 = 90;
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();

  /* USER CODE BEGIN 2 */
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
	htim1.Instance->CCR1 = dutyCycle1;
	dutyCycle1 += 10;
	if(dutyCycle1 > 90)dutyCycle1 = 10;
		
	htim1.Instance->CCR2 = dutyCycle2;
	dutyCycle2 -= 10;
	if(dutyCycle2 < 10)dutyCycle2 = 90;
		
	htim1.Instance->CCR3 = dutyCycle3;
	dutyCycle3 += 10;
	if(dutyCycle3 > 90)dutyCycle3 = 10;
		
	htim1.Instance->CCR4 = dutyCycle4;
	dutyCycle4 -= 10;
	if(dutyCycle4 < 10)dutyCycle4 = 90;
		
	HAL_Delay(1);	
  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

Berikut hasil signal PWM yang tergenerate.

_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + STM32CubeMX + Keil: DAC

Buka aplikasi STM32CubeMX. Lalu buat New Project

Pilih tipe mikrokontroller sesuai dengan tipe STM32F4 Discovery yaitu STM32F407VG

Lakukan setting pada pin yang akan kita gunakan.

Setelah itu generate source code, beri nama project dan setting toolchain MDK-ARM V5. Kemudian open project. Buka main.c


int main(void)
{

  /* USER CODE BEGIN 1 */
	uint32_t value = 100;
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DAC_Init();

  /* USER CODE BEGIN 2 */
	HAL_DAC_Start(&hdac, DAC_CHANNEL_1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
	/* USER CODE BEGIN 3 */
	HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_8B_R, value);
	value+=15;	
  if(value>255)value=100;
	HAL_Delay(500);
  }
  /* USER CODE END 3 */

}

_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + STM32CubeMX + Keil: ADC Continuous Conversion

Berikut spesifikasi ADC dari STM32.
http://embedded-lab.com/blog/stm32-adc-2/

Buka aplikasi STM32CubeMX lalu buat project baru dan buat pengaturan sebagai berikut. Kita pilih ADC2_IN2.

Pada tab Configure klik ADC2.

Lakukan pengaturan sebagai berikut.

Klik OK lalu generate source code. Jangan lupa beri nama project dan setting toolchain MDK-ARM V5. Setelah itu, open project. Buka main.c.
Berikut kode pada main.c

int main(void)
{

  /* USER CODE BEGIN 1 */
	uint32_t adcValue; 
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC2_Init();

  /* USER CODE BEGIN 2 */
	HAL_ADC_Start(&hadc2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
	
  /* USER CODE BEGIN 3 */
	adcValue = HAL_ADC_GetValue(&hadc2);
  }
  /* USER CODE END 3 */

}

_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + STM32CubeMX + Keil: GPIO

Pada kesempatan kali ini kita akan mencoba mengakses input dan output dengan memanfaatkan LED dan push button yang ada pada STM32F4 Discovery.
Buka aplikasi STM32CubeMX. Lalu buat New Project

Pilih tipe mikrokontroller sesuai dengan tipe STM32F4 Discovery yaitu STM32F407VG

Lakukan setting pada pin yang akan kita gunakan.

Pada tab configuration, klik GPIO dan masukan user label yang akan kita gunakan sebagai berikut.

Setelah itu Generate program.

Berilah nama project dan ganti toolchain menjadi MDK-ARM V5.

Setelah itu open project.

Setelah open project buka main.c

Setelah itu tambahkan kode berikut. Kita akan membuat aplikasi jika push button ditekan 1 kali maka LED akan berkedip. Ditekan kedua kali LED akan berkedip bergantian.

uint8_t counter;
uint8_t i=0;
uint16_t buffer1 = LD0_Pin;

if (HAL_GPIO_ReadPin(PB0_GPIO_Port, PB0_Pin))
{
	while(HAL_GPIO_ReadPin(PB0_GPIO_Port, PB0_Pin));
	counter++;
}

if(counter == 1)
{
	HAL_GPIO_TogglePin(LD0_GPIO_Port,LD0_Pin);
	HAL_GPIO_TogglePin(LD1_GPIO_Port,LD1_Pin);
	HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
	HAL_GPIO_TogglePin(LD3_GPIO_Port,LD3_Pin);
	HAL_Delay(500);
}
else if(counter == 2)
{
	buffer1 = LD0_Pin;
	for(i=0;i&lt;4;i++)
	{
		HAL_GPIO_WritePin(LD0_GPIO_Port, buffer1, GPIO_PIN_SET);
		HAL_Delay(100);
		HAL_GPIO_WritePin(LD0_GPIO_Port, buffer1, GPIO_PIN_RESET);
		buffer1&lt; 2)
{
	counter = 0;
}

Berikut kode lengkapnya.

/**
  ******************************************************************************
  * File Name          : main.c
  * Description        : Main program body
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */
	uint8_t counter;
	uint8_t i=0;
	uint16_t buffer1 = LD0_Pin;
  /* USER CODE END 1 */

  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
	
		if (HAL_GPIO_ReadPin(PB0_GPIO_Port, PB0_Pin))
		{
			while(HAL_GPIO_ReadPin(PB0_GPIO_Port, PB0_Pin));
			counter++;
		}
		
		if(counter == 1)
		{
			HAL_GPIO_TogglePin(LD0_GPIO_Port,LD0_Pin);
			HAL_GPIO_TogglePin(LD1_GPIO_Port,LD1_Pin);
			HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
			HAL_GPIO_TogglePin(LD3_GPIO_Port,LD3_Pin);
			HAL_Delay(500);
		}
		else if(counter == 2)
		{
			buffer1 = LD0_Pin;
			for(i=0;i&lt;4;i++)
			{
				HAL_GPIO_WritePin(LD0_GPIO_Port, buffer1, GPIO_PIN_SET);
				HAL_Delay(100);
				HAL_GPIO_WritePin(LD0_GPIO_Port, buffer1, GPIO_PIN_RESET);
				buffer1&lt; 2)
		{
			counter = 0;
		}
  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 188;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&amp;RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&amp;RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, LD0_Pin|LD1_Pin|LD2_Pin|LD3_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : PB0_Pin */
  GPIO_InitStruct.Pin = PB0_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(PB0_GPIO_Port, &amp;GPIO_InitStruct);

  /*Configure GPIO pins : LD0_Pin LD1_Pin LD2_Pin LD3_Pin */
  GPIO_InitStruct.Pin = LD0_Pin|LD1_Pin|LD2_Pin|LD3_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &amp;GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler */ 
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/**
  * @}
  */ 

/**
  * @}
*/ 

/*****************************END OF FILE****/

_______________________________________________________________
referensi: youtube.com/channel/UC-CuJ6qKst9-8Z-EXjoYK3Q/videos

STM32F4 Discovery + Keil: Setting ST-Link

Dari uVision Keil kita bisa langsung memprogram STM32F4 Discovery melalui USB. Terlebih dahulu kita lakukan pengaturan sebagai berikut.

Pilih ST-Link Debugger kemudian klik setting.

Ganti Port menjadi SW