Tampilkan postingan dengan label stm32f4 discovery. Tampilkan semua postingan
Tampilkan postingan dengan label stm32f4 discovery. Tampilkan semua postingan

Kamis, 29 September 2016

Serial USART Interrupt pada STM32F4 Discovery

Berdasarkan pengalaman, interupt biasanya sangat dibutuhkan untuk beberapa project. Terutama project yang sifatnya multi tasking. Mangkanya perlu pemahaman tentang interupt yang cukup bagi developer microcontroller. Dan biasanya, seringkali saya memakai USART mode interupt pada semua project microcontroller saya sejak jaman kuliah, karena lebih mudah dan 99.99% data diterima dengan baik(yang penting cable noise free lah). 

Nah, pada tulisan kali ini, saya ingin share sedikit cara penggunaaan interupt ini. Saya akan mencoba menyalakan lampu dan pembacaan ADC dari hyperminal. Ada 4 user IO led di STM32F4 Discovery. Saya ingin mencoba menyalak LED satu persatu, nyala semua, dan mematikan semua LED. Sedangakn untuk ADC, saya akan membaca tegangananalog dari potensio yang ada pada Pin A2. 

Untuk Inisialisasi USART, bisa dilihat dibawah ini:


void init_USART1(uint32_t baudrate){

    /* This is a concept that has to do with the libraries provided by ST
     * to make development easier the have made up something similar to
     * classes, called TypeDefs, which actually just define the common
     * parameters that every peripheral needs to work correctly
     *
     * They make our life easier because we don't have to mess around with
     * the low level stuff of setting bits in the correct registers
     */

    GPIO_InitTypeDef GPIO_InitStruct; // this is for the GPIO pins used as TX and RX
    USART_InitTypeDef USART_InitStruct; // this is for the USART1 initilization
    NVIC_InitTypeDef NVIC_InitStructure; // this is used to configure the NVIC (nested vector interrupt controller)

    /* enable APB2 peripheral clock for USART1
     * note that only USART1 and USART6 are connected to APB2
     * the other USARTs are connected to APB1
     */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

    /* enable the peripheral clock for the pins used by
     * USART1, PB6 for TX and PB7 for RX
     */

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    /* This sequence sets up the TX and RX pins
     * so they work correctly with the USART1 peripheral
     */

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // Pins 6 (TX) and 7 (RX) are used
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;             // the pins are configured as alternate function so the USART peripheral has access to them
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;        // this defines the IO speed and has nothing to do with the baudrate!
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;            // this defines the output type as push pull mode (as opposed to open drain)
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;            // this activates the pullup resistors on the IO pins
    GPIO_Init(GPIOB, &GPIO_InitStruct);                    // now all the values are passed to the GPIO_Init() function which sets the GPIO registers

    /* The RX and TX pins are now connected to their AF
     * so that the USART1 can take over control of the
     * pins
     */

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); //
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

    /* Now the USART_InitStruct is used to define the
     * properties of USART1
     */

    USART_InitStruct.USART_BaudRate = baudrate;                // the baudrate is set to the value we passed into this init function
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;// we want the data frame size to be 8 bits (standard)
    USART_InitStruct.USART_StopBits = USART_StopBits_1;        // we want 1 stop bit (standard)
    USART_InitStruct.USART_Parity = USART_Parity_No;        // we don't want a parity bit (standard)
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // we want to enable the transmitter and the receiver
    USART_Init(USART1, &USART_InitStruct);                    // again all the properties are passed to the USART_Init function which takes care of all the bit setting


    /* Here the USART1 receive interrupt is enabled
     * and the interrupt controller is configured
     * to jump to the USART1_IRQHandler() function
     * if the USART1 receive interrupt occurs
     */

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // enable the USART1 receive interrupt

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         // we want to configure the USART1 interrupts
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// this sets the priority group of the USART1 interrupts
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         // this sets the subpriority inside the group
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // the USART1 interrupts are globally enabled
    NVIC_Init(&NVIC_InitStructure);                             // the properties are passed to the NVIC_Init function which takes care of the low level stuff

    // finally this enables the complete USART1 peripheral
    USART_Cmd(USART1, ENABLE);
}

 Jika terjadi penerimaan data dari USART , maka akan terjadi interupt dan siklus program akan masuk ke vector interupt serial. Vector interupt dalam codingan ini adalah sebagai berikut:

void USART1_IRQHandler(void){

    // check if the USART1 receive interrupt flag was set
    if( USART_GetITStatus(USART1, USART_IT_RXNE) ){

        static uint8_t cnt = 0; // this counter is used to determine the string length
        char t = USART1->DR; // the character from the USART1 data register is saved in t

        if(t=='q')
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_12);
            GPIO_ResetBits(GPIOD, GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
        }
        else if(t=='w')
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_13);
            GPIO_ResetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_14|GPIO_Pin_15);
        }
        else if(t=='e')
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_14);
            GPIO_ResetBits(GPIOD, GPIO_Pin_13|GPIO_Pin_12|GPIO_Pin_15);
        }
        else if(t=='r')
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_15);
            GPIO_ResetBits(GPIOD, GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_12);
        }
        else if(t=='t')
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
        }
        else if(t=='x')
        {
            GPIO_ResetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
        }
        else if(t=='a')
        {
            voltage=(3300*ADC3ConvertedValue)/4095;
            float_print("Voltage =", voltage);
        }

    }
}

Saya akan mengontrol LED dengan karakter sederhana seperti diatas, tanpa protokol yang aneh aneh berhubung hanya menggunakan 1 microcontroller. Yang lumayan menjadi masalah disini adalah fungsi "sprint" dari library stdio tidak bisa untuk mengirimkan data dalam bentuk float. Hal ini sedikit berbeda dengan Library stdio pada IDE untuk atmelAVR yaitu codeVision VAR yang bisa digunakan untuk processing string dari variable float. Untuk mengatasi hal tersebut, saya membuat fungsi sederhana, yang lumayan efektif lah untuk kasus ini, untuk mengirimkan hasil konversi pembacaan tegangan ADC. Berikut fungsi yang saya buat:

void float_print(char* kalimat, int float_value)
{
    char buffer[20], buffer2[50];
    int bigvalue;
    int smallvalue;

    bigvalue=float_value/1000;//ini berisi angka di depan tanda koma
    smallvalue=(float_value%1000)/10;//ini berisi angka dibelakang koma
        sprintf(buffer,("%d.%d"),bigvalue, smallvalue);
    memset(buffer2,0,strlen(buffer2));//clear all memory
    strcat(buffer2,kalimat);//string "kalimat" ditambahkan ke string "buffer2"
    strcat(buffer2,buffer);//string "buffer" ditambahkan ke string "buffer2" 
    strcat(buffer2," volt \n\r");
    USART_puts(USART1, buffer2);
    memset(buffer2,0,strlen(buffer2));//clear all memory
}

Berikut hasil akhir di hyperterminal.



 Video nya juga bisa dilihat di youtube.



Gitu saja lah, untuk main.c nya bisa di download disini ya.

Selasa, 27 September 2016

Analog Digital COnverter ADC dan Serial Communication USART pada STM32F4 Discovery

Kali ini, saya akan membahas sedikit tentang ADC yang ada pada STM32F4 Discovery board. ADC yang digunakan disini adalah 12bit, sehingga lumayan presisi lah untuk sensor sensor tertentu seperti loadcell atau sensor lain. STM32 mempunyai 3 buah ADC inbuilt, yang dimana tiap ADC dimultiplex dengan 16 channel. Jadi totalnya, STM32F4 mempunyai 48 ADC channel. Konfigurasi pin I/O yang bisa digunakan untuk ADC adalah seperti dibawah ini.


Sumber : www.stm32f4-discovery.net/2014/04/library-06-ad-converter-on-stm32f4xx/

Tentunya biasanya kita tidaka akan menggunakan itu semua. Tapi ada bebrapa aplikasi tertentu yang sepertinya akan menggunakan banyak ADC, tapi kayaknya tidak usah dibahas. hehehe. Tapi sepertinya yang perlu digaris bawahi adalah resolusi dari ADC ini yang lumayan tinggi, yaitu 12 bit, atau hitungan desimal nya bisa 4095. Seumpama saja kita mempunyai tegangan referensi STM32F4, yaitu 3.3v, maka kita bisa mendeteksi perubahan tegangan 0.0008 volt. Kayaknya bagus untuk DSP kan. 

 Langsung saja lah, kita akan bahas cara penggunaanya. Disini saya fokus pada ADC nya, untuk USART nya, akan dibahas dilain postingan. Disini, saya akan menggunakan ADC dengan mode DMA. kenapa mode DMA? karena mode DMA (Direct Memory Access) tidak terlalu membebani CPU. Jadi, register dari pembacaan ADC akan langsung dicopy ke memory/variable yang telah kita deklarasikan sendiri. Selain tidak membebani CPU, seharusnya penggunaan ADC juga akan bekerja lebih cepat karena tidak perlu masuk CPU, tapi langsung direct transfer memory. Mode ini cocok untuk pengolahan sinyal dengan frekwensi yang tinggi. 

Berikut script inisialisasi ADC mode DMA.

void ADC3_CH2_DMA_Config(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;
  /* Enable ADC3, DMA2 and GPIO clocks ****************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 | RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
  /* DMA2 Stream0 channel2 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_Channel_2;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC3_DR_ADDRESS;
  //ADC3Converted value adalah variable yang saya deklarasikan sendiri. 
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC3ConvertedValue;  
  //Ini adalah mode ADC kita, yaitu DMA
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
  DMA_Cmd(DMA2_Stream0, ENABLE);
  /* Configure ADC3 Channel2 pin as analog input ******************************/
  // konfigurasi pin yang kita pakai harap dilihat di table channel ADC, sehingga kita bisa memilih
  // pin yang free, yang bisa kita gunakan untuk ADC.

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);
  /* ADC3 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC3, &ADC_InitStructure);
  /* ADC3 regular channel2 configuration *************************************/
  ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_3Cycles);
 /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE);
  /* Enable ADC3 DMA */
  ADC_DMACmd(ADC3, ENABLE);
  /* Enable ADC3 */
  ADC_Cmd(ADC3, ENABLE);
}

Dari Script diatas, bisa dilihat bahwa  saya menggunakan variabel "ADC3ConvertedValue" untuk menyimpan limpahan data dari DMA stream yang berisi data pembacaan memory "ADC3_DR_ADDRESS" yang berisi nilai pembacaan ADC.

Jika ada yang bertanya apakah saya membuat semua ini sendiri, jawabanya "tentu tidak semua". Enaknya CoIDE adalah, kita diberi examplae dari component yang ada CoIDE. Dan sepertinya semuanya bekerja dengan baik. Tapi tentu saja ada beberapa yang perlu disesuaikan dengan keperluan, berhubung setiap project harus disesuaikan dengan kebutuhanya masing masing. Berikut adalah hasil akhir dari dari pembacaan ADC di hyperterminal.



Silahkan lihat video di youtube untuk lebih jelasnya.


Karena kodingannya lumayan panjang, saya tidak menuliskan kodenya disini, karena akan menuh menuhin halaman. Untuk file lengkapnya, silakan download disini.

Sekian terima kasih, kalau ada kritik dan sar, silakan ditulis dibawah ya.

Senin, 26 September 2016

STM32F4 Discovery GPIO dengan menggunakan CoIDE dari CooCox

Hari ini saya iseng iseng membuka kenangan lama dari board STM32F4 Discovery yang sudah lama menghuni plastik kresek koleksi komponen komponen jaman dahulu kala. Celakanya, saya nyari nyari Keil di laptop kok g ada, ternyata sudah saya uninstall dan saya g punya backup installer. Akhirnya ya sudah lah, cari alternatif apa yang ada di hardisk, dan akhirnya saya menemukan CoIDE dari CooCox, dan memang bener bener cocox IDE ini. Saya rasa kok g seribet keil dalam add library dan semacamnya. Ok lah, kita langsung ke pembahasan.

CoIDE adalah IDE keluaran CooCox, yang kita tahu coocox ini yang bikin RTOS, yang bisa digunakan untuk develepo berbagai macam chip mulai dari ARM, Atmel, Energy Micro, Freescale, Holtex, TI, NXP, Nuvoton dsb. Dan yang lebih bagus lagi, software ini free. Benar benar free. Lihat saja screenshot dibawah ini. Untuk mendowload installernya, silakan ke www.coocox.org. 


Ok lah, kita langsung saja mencoba CoIDE. Selesai mengisntall, yang cara mengisntal nya juga biasa saja, kita akan membuat project baru yang sederhana, yaitu GPIO. Berikut step by step cara membuat project baru di CoIDE.
  1. Cari Klik Tab Project, dan klik New Project.
  2. Selanjutanya, kita masuk ke nama project. Disini saya memakai nama "gpio" sebagai nama project, dan tick  use default path.
  3.  Disini, kita diberi pilihan kita akan menggunakan chip, atau board jadi. Disini saya menggunakan STM32F4 discovery. Searusnya saya memilih board, tapi ternyata STM32F4 tidak ada pilihan nya di board. Jadi kita masuk chip saja.
  4. Kemudian pilih chip yang kita gunakan, di STM32F4 Discovery menggunakan STM32F407VG sebagai chip utamanya.
  5. Daaaannnn....ini lah hasilnya. Wellcome to new project. Kelihatan cukup menarik bukan. disitu tersedia component, yang berupa library, yang bisa kita gunakan untuk membuat project. Pada awalnya saya pikir, software ini seperti CodevisionAVR yang akan mengenerate script otomatis untuk kita. Tapi ternyata tidak, walaupun kita diberi pilihan library di situ, kita tetap akan menemukan main.c yang kosong. Tapi lumayan lah, kita tidak perlu menambah kan file file library ke folder project kita dengan cara manual. Untuk projcet GPIO ini, saya hanya menggunakan library yang sama butuhkan. Disini saya menggunakan C Library, M4 CMSIS Core, CMSIS BBOT, RCC, GPIO, dan MISC. Bagusnya software ini, dia akan memberi peringatan ketika kita memerlukan untuk menambah library lain yang kurang, jika kita akan memilih suatu library. semoga ente yang baca bakal paham lah apa maksud ane.
  6. Langsung saja kita ke main.c. Saya akan membuat aplikasi GPIO sederhana yang yang terdiri dari led dan button yang sudah ada di board STM32F4 Discovery.Berikut sedikit penjelas wiring dari bosrd discovery ini.
                 Push button biru terhubung ke      Port A0
                 led green(LD4)                               PD12
                 led orange(LD3)                            PD13
                 led red(LD5)                                  PD14
                 led blue (LD6)                               PD15
 Dan berikut script project gpio saya. Disini saya kayaknya tidak perlu saya jelaskan, lihat saja lah
dibawah.

#include "stm32f4xx.h" //library stm32f4
#include "stm32f4xx_gpio.h"//library gpio
#include "stm32f4xx_rcc.h" //library reset dan clok

GPIO_InitTypeDef  GPIO_InitStructure;
void Delay(__IO uint32_t nCount);
uint8_t d;

int main(void)
{

    /*led di board stm32f4 discovery terhubung ke Port D dengan konfigurasi
         * ----led green(LD4)    PD12
         * ----led orange(LD3)   PD13
         * ----led red(LD5)    PD14
         * ----led blue (LD6)    PD15
         *
         * push button di board stm32f4 discovery
         * ---- push button user warna biru PA0
         * */

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); // enable clock untuk portD
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); // enable clock untuk portA

    /* Configure PD0, PD12, PD13, PD14 and PD15 in output pushpull mode */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    while(1)
    {
        //jika Button ditekan, maka LED biru dan merah akan ON. jika tidak ditekan,
        // LED hijau dan orange    akan menyala.
 
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)!=Bit_SET)
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13);
            GPIO_ResetBits(GPIOD, GPIO_Pin_14|GPIO_Pin_15);
        }
        else
        {
            GPIO_ResetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13);
            GPIO_SetBits(GPIOD, GPIO_Pin_14|GPIO_Pin_15);
        }
        //Delay(0x0FFFFF);
    }
}
void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
 }
}


Setelah itu, bisa di compile dan di download. Sebelum kita download file ke chip. ada sedikit yag perlu di
setting. SIlakan klik tab "View"  --->>> Configuration.Ada sedikit perubahan yang saya lakukan. Yaitu di
tab Link, saya akan menggunkan "Use Base C Library". Dan di tab "Debugger", saya menggunakan "STLink" port "SWD" yang merupakan fitur bawaan STM32F4 Discovery. Lebih jelasnya, silakan melihat gambar dibawah ini:


                                                               Tampilan tab "Link"


                                                             Tampilan tab "Debugger"

Hasilnya, monggo cek video berikut. Ketika puh button biru ditekan LED btu dan merah akan menyala. Simple bukan. hehehe...


Cukup lah, g usah banyak banyak. Capek ngetiknya.







Rabu, 12 Februari 2014

Library koneksi LCD 16x2 HD44780 untuk STM32F4 board

                Pada posting kali ini, kita akan mencoba untuk menghubungkan LCD 16x2 HD44780 (atau clone-nya) dengan board STM32F4 Discovery. Mode yang dipakai adalah mode 3 pin kontrol dan 4 pin data. Semua pin akan dikoneksikan ke PORT E. Bagaimana kah rangkaian untuk memakai LCD? liat aja gambar di bawah ini.



                Disitu tampak kalau ada variable resistor yang terpasang di 3 pin LCD yang diunakan untuk mengatur contras dari LCD yang dipakai. Konfigurasi tersebut bisa di rubah ke port lain dengan meng-edit di file hd44780.h.  Konfigurasi pin dari LCD dan board STM32F4 adalah sebagai berikut:
    - LCD_D4 >>> PORTE 14
    - LCD_D5 >>> PORTE 13
    - LCD_D6 >>> PORTE 11
    - LCD_D7 >>> PORTE 12
    - LCD_RS >>> PORTE 8
    - LCD_RW >>> PORTE 7
    - LCD_EN >>> PORTE 10
Terus terang, library ini bukan buatan saya sendiri, tapi saya copy dari hasil searching di internet, dan saya juga lupa dari mana saya mendapatkanya, berhubung banyaknya library LCD yang saya coba. Tapi berikut library yang saya peroleh:

//******************************************************************************
//    THE SOFTWARE INCLUDED IN THIS FILE IS FOR GUIDANCE ONLY.
//    AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT
//    OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
//    FROM USE OF THIS SOFTWARE.
//******************************************************************************

//##############################################################################
// simpan file ini dengan nama hd44780.h
//##############################################################################

//****************************************************************************//
//#include "main.h"


#define LCD_GPIO GPIOE
#define LCD_CLK_LINE RCC_AHB1Periph_GPIOE

#define LCD_D4 GPIO_Pin_14
#define LCD_D5 GPIO_Pin_13
#define LCD_D6 GPIO_Pin_11
#define LCD_D7 GPIO_Pin_12

#define LCD_RS GPIO_Pin_8
#define LCD_RW GPIO_Pin_7
#define LCD_EN GPIO_Pin_10
//******************************************************************************//


#define HD44780_CLEAR                                          0x01

#define HD44780_HOME                                           0x02

#define HD44780_ENTRY_MODE                            0x04
        #define HD44780_EM_SHIFT_CURSOR          0
        #define HD44780_EM_SHIFT_DISPLAY         1
        #define HD44780_EM_DECREMENT               0
        #define HD44780_EM_INCREMENT               2

#define HD44780_DISPLAY_ONOFF                      0x08
        #define HD44780_DISPLAY_OFF                    0
        #define HD44780_DISPLAY_ON                     4
        #define HD44780_CURSOR_OFF                    0
        #define HD44780_CURSOR_ON                      2
        #define HD44780_CURSOR_NOBLINK          0
        #define HD44780_CURSOR_BLINK               1

#define HD44780_DISPLAY_CURSOR_SHIFT 0x10
        #define HD44780_SHIFT_CURSOR               0
        #define HD44780_SHIFT_DISPLAY              8
        #define HD44780_SHIFT_LEFT                     0
        #define HD44780_SHIFT_RIGHT                  4

#define HD44780_FUNCTION_SET                       0x20
        #define HD44780_FONT5x7                            0
        #define HD44780_FONT5x10                          4
        #define HD44780_ONE_LINE                         0
        #define HD44780_TWO_LINE                         8
        #define HD44780_4_BIT                                  0
        #define HD44780_8_BIT                                  16

#define HD44780_CGRAM_SET                                    0x40

#define HD44780_DDRAM_SET                                    0x80

//##############################################################
void lcd_init(void);
void lcd_cls(void);
void lcd_str(unsigned char * text);
void lcd_strxy(unsigned char * text, unsigned char x, unsigned char y);
void lcd_locate(unsigned char x, unsigned char y);
void lcd_int(int n);
void lcd_intxy(int n, unsigned char x, unsigned char y);
//unsigned char* intToStr(int n); 
//###############################################################

void lcd_writedata(unsigned char dataToWrite);
void lcd_writecommand(unsigned char commandToWrite);
void lcd_writebinary(unsigned int var, unsigned char bitCount);
void lcd_addchar (unsigned char chrNum, unsigned char n, const unsigned char *p);

Sedangkan Source dari library diatas adalah sebagai berikut:

/*simpan file ini dengan naman hd44780.c*/
#include "hd44780.h"
#include "stm32f4xx_gpio.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "stm32f4_discovery.h"

GPIO_InitTypeDef GPIO_InitStructure;

//-----------------------------------------------------------------------------
void lcd_writenibble(unsigned char nibbleToWrite)
{
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_SET);
  GPIO_WriteBit(LCD_GPIO, LCD_D4,(BitAction) (nibbleToWrite & 0x01));
  GPIO_WriteBit(LCD_GPIO, LCD_D5,(BitAction)(nibbleToWrite & 0x02));
  GPIO_WriteBit(LCD_GPIO, LCD_D6,(BitAction)(nibbleToWrite & 0x04));
  GPIO_WriteBit(LCD_GPIO, LCD_D7,(BitAction)(nibbleToWrite & 0x08));
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_RESET);
}
//-----------------------------------------------------------------------------
unsigned char LCD_ReadNibble(void)
{
  unsigned char tmp = 0;
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_SET);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D4) << 0);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D5) << 1);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D6) << 2);
  tmp |= (GPIO_ReadInputDataBit(LCD_GPIO, LCD_D7) << 3);
  GPIO_WriteBit(LCD_GPIO, LCD_EN, Bit_RESET);
  return tmp;
}
//-----------------------------------------------------------------------------
unsigned char LCD_ReadStatus(void)
{
  unsigned char status = 0;

    GPIO_InitStructure.GPIO_Pin   =  LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7;
    GPIO_InitStructure.GPIO_Mode  =  GPIO_Mode_IN;
    GPIO_Init(LCD_GPIO, &GPIO_InitStructure);

    GPIO_WriteBit(LCD_GPIO, LCD_RW, Bit_SET);
    GPIO_WriteBit(LCD_GPIO, LCD_RS, Bit_RESET);

    status |= (LCD_ReadNibble() << 4);
    status |= LCD_ReadNibble();

    GPIO_InitStructure.GPIO_Pin   =  LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Init(LCD_GPIO, &GPIO_InitStructure);

  return status;

//-----------------------------------------------------------------------------
void lcd_writedata(unsigned char dataToWrite)
{
  GPIO_WriteBit(LCD_GPIO, LCD_RW, Bit_RESET);
  GPIO_WriteBit(LCD_GPIO, LCD_RS, Bit_SET);

  lcd_writenibble(dataToWrite >> 4);
  lcd_writenibble(dataToWrite & 0x0F);

  while(LCD_ReadStatus() & 0x80);
}
//-----------------------------------------------------------------------------
void lcd_writecommand(unsigned char commandToWrite)
{
  GPIO_WriteBit(LCD_GPIO, LCD_RW | LCD_RS, Bit_RESET);
  lcd_writenibble(commandToWrite >> 4);
  lcd_writenibble(commandToWrite & 0x0F);

  while(LCD_ReadStatus() & 0x80);
}
//-----------------------------------------------------------------------------
void lcd_str(unsigned char * text)
{
  while(*text)
    lcd_writedata(*text++);

//-----------------------------------------------------------------------------
void lcd_locate(unsigned char x, unsigned char y)
{
  lcd_writecommand(HD44780_DDRAM_SET | (x + (0x40 * y)));
}
//-----------------------------------------------------------------------------
void lcd_strxy(unsigned char * text, unsigned char x, unsigned char y)
{
  lcd_locate(x,y);
  while(*text)
    lcd_writedata(*text++);

//-----------------------------------------------------------------------------
void lcd_writebinary(unsigned int var, unsigned char bitCount)
{
  signed char i;

  for(i = (bitCount - 1); i >= 0; i--)
     {
     lcd_writedata((var & (1 << i))?'1':'0');
     }

//-----------------------------------------------------------------------------
void LCD_ShiftLeft(void)
{
  lcd_writecommand(HD44780_DISPLAY_CURSOR_SHIFT | HD44780_SHIFT_LEFT | HD44780_SHIFT_DISPLAY);
}
//-----------------------------------------------------------------------------
void LCD_ShiftRight(void)
{
  lcd_writecommand(HD44780_DISPLAY_CURSOR_SHIFT | HD44780_SHIFT_RIGHT | HD44780_SHIFT_DISPLAY);
}
//-----------------------------------------------------------------------------
void lcd_init(void)
{
  volatile unsigned char i = 0;
  volatile unsigned int delayCnt = 0;
  RCC_AHB1PeriphClockCmd(LCD_CLK_LINE, ENABLE);
  GPIO_InitStructure.GPIO_Pin = LCD_D4|LCD_D5|LCD_D6|LCD_D7|LCD_RS|LCD_RW|LCD_EN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

  GPIO_Init(LCD_GPIO, &GPIO_InitStructure);

  GPIO_ResetBits(LCD_GPIO, LCD_RS | LCD_EN | LCD_RW);

  for(delayCnt = 0; delayCnt < 300000; delayCnt++);

  for(i = 0; i < 3; i++) {
    lcd_writenibble(0x03);
    for(delayCnt = 0; delayCnt < 30000; delayCnt++);
  }

  lcd_writenibble(0x02);

  for(delayCnt = 0; delayCnt < 6000; delayCnt++);

  lcd_writecommand(HD44780_FUNCTION_SET |
                   HD44780_FONT5x7 |
                   HD44780_TWO_LINE |
                   HD44780_4_BIT);

  lcd_writecommand(HD44780_DISPLAY_ONOFF |
                   HD44780_DISPLAY_OFF);

  lcd_writecommand(HD44780_CLEAR);

  lcd_writecommand(HD44780_ENTRY_MODE |
                   HD44780_EM_SHIFT_CURSOR |
                   HD44780_EM_INCREMENT);

  lcd_writecommand(HD44780_DISPLAY_ONOFF |
                   HD44780_DISPLAY_ON |
                   HD44780_CURSOR_OFF |
                   HD44780_CURSOR_NOBLINK);
}
//-----------------------------------------------------------------------------
void lcd_addchar (unsigned char chrNum, unsigned char n, const unsigned char *p)
{
        lcd_writecommand(HD44780_CGRAM_SET | chrNum * 8);
        n *= 8;
        do
                lcd_writedata(*p++);
        while (--n);

//-----------------------------------------------------------------------------
void lcd_cls(void){
        lcd_writecommand(HD44780_CLEAR);
}

unsigned char* intToStr(int n)
{
     int i = 0;
     int j = 0;
   char *tmp = (char*)malloc(sizeof(char));
     unsigned char *ret = (unsigned char*)malloc(12);
   if(n<0 font="">
 *tmp = n%10+48;
 n-=n%10;
 n/=10;
 tmp++;
 i++;
}
*tmp = n+48;
i++;
while(i--){
 ret[j++] = *tmp--;
}
return ret;
}
void lcd_int(int a){
 unsigned short ch,first; //you need this to display 0 if there was any char

    //Get first char
    ch = a/10000;
    if(ch){
     lcd_writedata(48+ch);
     first = 1;
    }

    //Get second char
    ch = (a/1000)%10;
    if(ch || first){
     lcd_writedata(48+ch);
     first = 1;
    }

    //Get third char
    ch = (a/100)%10;
    if(ch || first){
     lcd_writedata(48+ch);
     first = 1;
    }

    //Get fourth char
    ch = (a/10)%10;
    if(ch || first){
     lcd_writedata(48+ch);
     //first = 1;                   //q
    }

    //Get fifth char
    ch = a%10;
    //if(ch || first)   //you dont need to check las one if ch is 0 then just display it, unless you dont want to then uncomment this line ("//q" line too)
     lcd_writedata(48+ch);
       // lcd_str(intToStr(n));
}

void lcd_intxy(int n, unsigned char x, unsigned char y)
{
        lcd_locate(x,y);
        lcd_int(n);
}

Dari sekian banyaknya fungsi, saya cuman baru make beberapa fungsi saja. Yang ditampilkan di postingan ini hanya untuk menampilkan karakter sdan string ke LCD saja. Pelan pelan saja, jangan buru buru. hehehe
Berikut Fungsi main.c dari project yang saya buat:

#include
#include
#include
#include
#include

int main(void)
{
  lcd_init(); 
  lcd_cls();
  lcd_strxy("_ardiansm",0,0);
  lcd_strxy("CircuitDrilling",0,1);
}

Sudah dulu ya, cukup begitu saja. Barangkali ada yang punya pikiran, kenapa g dijelasin proses komunikasi data antara LCD dan board STM32F4 nya. Karena saya punya pikiran, LCD 16x2 ini sudah banyak sekali yang membahas, dan sebagian besar aplikasi LCD ini hanya untuk display, hanya penting pada beberapa aplikasi HMI saja. Dan lagi pula, kebanyakan orang juga jarang ada yang mau baca detail komunikasinya, cukup copy paste library, udah deh selasai.


Ditunggu komen dan kritiknya yak.

Senin, 10 Februari 2014

Membuat project baru pada Keil uVision untuk pemrograman board STM32F4 Discovery (New Project in uVision STM32F4 Discovery)

Hai hai...kembali lagi bersama saya dengan tampilan blog yang baru dengan nama CircuitDrilling. Apa filosofi dari Circuit Drilling? Bodo amat apalah arti sebuah nama, walau sebenarnya nama juga penting buat marketing. Ok lah, setelah sekian lama vakum dari dunia blogger, sekarang saya kembali lagi exsist dengan tema blog yang lebih specific, yaitu Electronics, Drilling, dan pengalaman perjalanan saya mengarungi kehidupan per-mbolangan.

Postingan terakhir saya sebelum ini adalah tentang pemrograman ARM Cortex M4 dengan menggunakan WinArm, tapi karena alasa kepratisan, maka saya mulai berpindah ke software yang lebih user friendly, yaitu KEIL uVision.


Tidak perlu panjang lebar tentang software ini, yang jelas lebih mudah dari pada WinARM. Tapi dengan konsekwnsi kita harus beli versi berlisensi nya. Tapi untuk Trial, ada juga versi eval nya, kalau mau download silakan di www.keil.com , atau untuk versi gratisan yang tidak resmi alias crack2an, silakan saja cari 4shared atau tempat lain, tang jelas banyak yang makai IDE ini kok.

Setelah diinstal dan dibaca readme nya, tampilan uVision adalah sebagai berikut.



Bingung kan, kok kosong melompong. hahaha. Software ini berbeda dengan software yang biasa saya gunakan untuk pemrograman microcontroller AVR ATMega family, yaitu CodeVision AVR, yang dimana CV AVR mempunyai code wizard yang akan menggenerate coding secara otomatis. Di uVision, tidak disediakan fasilitas seperti itu. Kenapa? tak taulah awak, tapi yang jelas menurut awak, yang namanya codewizaerd itu adalah fasilitas PEMBODOHAN (hahaha), walau memang bisa dibilang sangat praktis.

Ada yang lupa saudara, sebelum membuat project baru, sangat saya sarankan untuk mendownload file file update dari UVision yang bisa di download disini , file tersebut berisi library library  yang  kita perlukan selain library asli dari software uVision nya.

Langsung saja, untuk membuat project baru, kita klik tab Project  > New uVision Project , maka akan keluar pop up yang meminta kita untuk menentukan tempat kita menaruh file project kita. Di laptop awak, akan saya coba untuk menyimpanya di drive D:/arm_dev , tapi kalo ente terserah. Beri nama yang mudah diingat sesui dengan tema project yang kita buat, project kita akan otomatis disimapn dengan ekstensi .uvproj. Kemudian klik Save. kemuadian akan muncul tampilan seperti ini :


Pop up tersebut digunakan untuk memilih tipe dari processor apa yang kita pakai. Berhubung saya memakai board STM32F4 Discovery, maka saya akan memilih STMicroelectronics >> STM32F407VG. Klik ok, dan kemudian akan muncul pertanyaan 'Copy 'startup_stm32f4xx.s' to Project Folder and Add File to Project?'? Yes, saya sangat ingin sekali menambahkan file penting tersebut. File tersebut digunakan sebagai parameter parameter dari chip yang kita pakai.

Akhirnya kita masuk ke project baru, tapi kok tetep kosong. Hahaha. Di uVision, kita benar benar membuat pemrograman dari nol, saran saya, untuk membuat pemrograman STM32F4 lebih cepat, siap siap dengan senjata Copy-Paste. Di window tersebut kita sudah melihat Target1, yaitu project sasaran eksekusi dari compiler maupun linker dan lain lain. Yang perlu kita lakukan sekarang adalah, kita perlu menambahkan sedikit setingan pada Target Options. Klik tap Projects >> Option for Target 'nama target' ( atau icon yang ada tongkat penyihir-nya), maka akan keluar popup seperti ini:


Di tab tersebut, ada yang perlu kita sesuaikan, antara lain:  
1. XTal (MHz) = 8.00 MHz (sesuai dengan xtal dari board, sebenarnya bisa di optimalkan sampe 160an MHz, tipa kita bahas nanti)
2. Centang Use MicroLIB
3. Centang IRAM2

Di tab Output, jangan lupa dicentang Create Hex File

Di tab C/C++, perlu banyak setingan. Bisa dilihat di bawah ini:
1. Define = USE_STDPERIPH_DRIVER , STM32F4XX
2. Optimation : Level 3
3. Centang One ELF Section per Function
4. Include path, lebih mudah untuk ditunjukkan dengan gambar. hahaha:


PERHATIAN : Di awal tadi, saya anggap ente ente sudah mendownload file library dari website ST, atau bila belum download silakan klik disini. Bila sudah, extrak file tersebut di sebuah folder yang tidak terlalu "dalam". maksudnya, kalau bisa di extrak di folder di drive D ata C, jangan dimasukin ke folder folder lagi. Semua folder yang terdapat pada include path tab, diambil dari hasil extrak file yang di download. 

Di tab ASM, selalu saya isi Define = USE_STDPERIPH_DRIVER , STM32F4XX

Di tab Debug, lihat saja gambar ini. ST-Link Debugger dipilih karena saya menggunakan debugger bawaan dari board STM32f4 Discovery.



Di tab Utilities , silakan saja liat gambar. hehehe


Oh iya ada 1 lagi yang lupa. Berdasarkan pengalaman, lebih baik copy stm32f4xx_syscfg.c dan system_stm32f4xx.c  ke folder dari project kita. File tersebut bisa dicopy file kita download sebelumnya (di folder src).

Ok, sekarang mari kita buat project sederhana di sini. Kita bisa saja buka example yang ada, tapi ngga greget kalo g bikin sendiri kan. Di sini kita buat aplikasi sederhana yang melibatkan I/O dari board STM32F4 Discovery. Pergi ke tab FILE >> New .Biar g lama, silakan copy saja file dibawah ini dan paste ke file baru tersebut.

#include // library setting I/O
#include //library pengaturan clock
#include

volatile char btns;

void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
/*Fungsi delay ini tidak presisi karena menggunakan metode TEKIRO alias teknik kiro kiro*/
uint32_t i;
for (i=0;i<42000 i="">
{}
i=0;
  }
}

void BTN_Init(void) 
{
/*user push button terhubung dengan PA.0*/
  RCC->AHB1ENR  |= ((1UL <<  0) );              /* Enable GPIOA clock         */

  GPIOA->MODER    &= ~((3UL <<; 2*0)  );         /* PA.0 is input              */
  GPIOA->OSPEEDR  &= ~((3UL << 2*0)  );         /* PA.0 is 50MHz Fast Speed   */
  GPIOA->OSPEEDR  |=  ((2UL << 2*0)  ); 
  GPIOA->PUPDR    &= ~((3UL << 2*0)  );         /* PA.0 is no Pull up         */
}
uint32_t BTN_Get(void) 
{
 return (GPIOA->IDR & (1UL << 0)); //cek nilai dari register IDR PA.0
}
void LED_Init(void)
{
/*LED terhubung ke PD.12, PD.13, PD.14, PD.15 */
RCC->AHB1ENR  |= ((1UL << 3) );         /* Enable GPIO port D clock                */
GPIOD->MODER    &= ~((3UL << 2*12) |
                       (3UL << 2*13) |
                       (3UL << 2*14) |
                       (3UL << 2*15)  );   /* PD.12..15 is output               */
  GPIOD->MODER    |=  ((1UL << 2*12) |
                       (1UL << 2*13) | 
                       (1UL << 2*14) | 
                       (1UL << 2*15)  ); 
  GPIOD->OTYPER   &= ~((1UL <<   12) |
                       (1UL <<   13) |
                       (1UL <<   14) |
                       (1UL <<   15)  );   /* PD.12..15 is output Push-Pull     */
GPIOD->OSPEEDR  &= ~((3UL << 2*12) |
                       (3UL << 2*13) |
                       (3UL << 2*14) |
                       (3UL << 2*15)  );   /* PD.12..15 is 50MHz Fast Speed     */
  GPIOD->OSPEEDR  |=  ((2UL << 2*12) |
                       (2UL << 2*13) | 
                       (2UL << 2*14) | 
                       (2UL << 2*15)  ); 
GPIOD->PUPDR    &= ~((3UL << 2*12) |
                       (3UL << 2*13) |
                       (3UL << 2*14) |
                       (3UL << 2*15)  );   /* PD.12..15 is Pull up              */
  GPIOD->PUPDR    |=  ((1UL << 2*12) |
                       (1UL << 2*13) | 
                       (1UL << 2*14) | 
                       (1UL << 2*15)  );  
}

int main(void)
{
/*
Fungis ini merupakan contoh sederhana dari STM32F4 Discovery. Jika user button ditekan, maka LED3, LED4, LED5, LED6 akan mati,
dan jika dilepas, LED3, LED4, LED5, LED6 akan menyala.
*/
  // Systemclock auf 168MHz (stm32F4Discovery mit 8MHz Quarz)
  SystemInit();
//INIT BUTTON AND LEDS
BTN_Init();
LED_Init();
while(1)
    {
   
btns = BTN_Get();
if(btns ==(1UL << 0))
{
btns=0;
GPIOD->BSRRH = 1UL << 12; GPIOD->BSRRH = 1UL << 13; GPIOD->BSRRH = 1UL << 14;GPIOD->BSRRH = 1UL << 15;
Delay(1000);
}
else
{
GPIOD->BSRRL = 1UL << 12; GPIOD<<BSRRL = 1UL << 13; GPIOD->BSRRL = 1UL << 14;GPIOD->BSRRL = 1UL << 15;
}
    }
}

Kemudian simpan dengan nama main.c di folder project kita. Kita juga perlu menambahkan beberapa file source ke dalam target atau project kita. Untuk memudahkan dalam proses pengenalan file, lebih baik kita pisahkan file ke beberapa group. Cara membuat adalah dengan cara klik kanan Target1 >> Add Group. Kita beri nama group baru tersebut dengan nama source dan source2. Kemudian tambahkan file ke dalam group dengan cara klik kanan nama group, misal source2 >> Add files to group 'source2'. Hasil dari penambahan file ke project adalah seperti gambar di bawah ini.



Setelah semua project di compile dan di built dengan tanpa menghasilkan error, maka project kita sipa untuk di Load ke board STM32F4 kita.

Cukup kayaknya tulisan ini. Mungkin ada beberapa orang yang baca tulisan ini berpikir "RIbet amat ya". Kalau misal ada yang punya cara lebih bagus, tolong di share di mari ya, kan sama sama belajarnya :D