Thông báo

Collapse
No announcement yet.

(Share) Cortex M3 từng bước tiếp cận.

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • (Share) Cortex M3 từng bước tiếp cận.

    Chào toàn thể các bác! Hiện nay vi điều khiển 32 bit không quá xa lạ với dân điện tử điều khiển. Dễ mua, giá cả phải chăng, công cụ lập trình đa dạng và sự hỗ trợ tốt của nhà sản xuất chip, tất cả những nguyên nhân đó góp phần làm cho arm ngày càng trở nên phổ biến, cộng đồng người sử dụng arm ngày một lớn lên.
    Việc học lập trình arm cho người mới tiếp cận không dễ dàng, không như các loại vi điều khiển 8bit trước đây. Rất nhiều chức năng được tích hợp trong 1 chíp duy nhất, sự đồ sộ về cấu trúc và số lượng các thanh ghi, khả năng tùy biến quá mềm dẻo của các ngoại vi. Tất cả sẽ rất thuận lợi cho người sử dụng viết ứng dụng nhưng chính điều đó gây lên khó khăn cho người mới tiếp cận.
    Đứng trên vị trí người mới tìm hiểu arm 32 bit em xin mạo muội đưa ra bài hướng dẫn chi tiết về các quá trình tiếp cận dòng vi điều khiển này mà cụ thể là dòng Cortex M3 cho các bạn mới có thể thuận lợi hơn khi nghiên cứu. Cá nhân em cũng mới tìm hiểu arm nên hiểu biết cũng có nhiều hạn chế. Vì vậy xin các bác cao thủ 32 bit xem, sửa và góp ý thêm những phần nào chưa chính xác, những phần còn thiếu để mọi người có chuẩn hóa thông tin từ bài viết này.
    Vì luồng này dành cho những người mới tìm hiểu arm, với những vấn đề gặp phải như em đã nêu nên mong mọi người thảo luận trên quan điểm góp ý chung tôn trọng lẫn nhau. Những ai có "nhu cầu" trao đổi thêm xin liên hệ trực tiếp với nhau. Tránh việc tranh cãi to tiếng làm loãng luồng.
    Tất cả những thông tin em cung cấp sau đây đều được em tổng hợp từ những bài viết trên mạng, từ tài liệu nước ngoài và một phần từ kinh nghiệm bản thân, nếu trong quá trình viết em ko trích dẫn luồng thông tin từ đâu thì xin các bác cũng bỏ qua cho lỗi này.
    Tât cả các thông tin em cung cấp chỉ là tài liệu để các bạn đọc và tham khảo. Em không chịu trách nhiệm do hậu quả do thông tin cung cấp. Em săn sàng nhận góp ý và thắc mắc từ mọi người qua mail vuxuansyhut@gmail.com

    Và sau đây là các phần thông tin em dự định sẽ cung cấp.
    1- Tổng quan về arm cortex M3
    2- Lập trình ứng dụng trên LPC1768
    2.1. Clock
    2.2. GPIO
    2.3. Timer
    2.4. SPI và giao tiếp thẻ SD
    2.5. Cấu trúc định dạng FAT32 và truy cập file trên thẻ SD
    2.6. Phát file Wave qua DAC

    Các phần trên tuy chưa đầy đủ cho các ngoại vi nhưng sẽ cung cấp 1 lượng thông tin bổ ích cho người dùng mới.

    Do em ban ngày phải đi làm nên thời gian không có nhiều trong khi đó khối lượng cung cấp như trên là khá lớn nên không tránh khỏi việc chậm trễ trong việc viết bài. Mong các bác thông cảm.

    Trân trọng !

    Giải pháp điện tử của bạn

  • #2
    Phần 1: Tổng quan về arm cortex M3

    Phần giới thiệu arm cortex M3 được giới thiệu chi tiết trên diễn đàn arm.vn
    Khi tìm hiểu một dòng vi điều khiển mới điều quan tâm đầu tiên của người sử dụng đó là khả năng xử lý của chip từ đó có sự so sánh với dòng vi điều khiển đã có, sau đó là các ngoại vi hỗ trợ. Nhiều khi công nghệ sản xuất và kiến trúc bên trong không được quan tâm nhiều. Nhưng để so sánh với dòng cũ thì ko thể bỏ qua cấu trúc lõi. Tham khảo các bài viết trên trang arm.vn em rút lại những điều ngắn gọn sau.

    Dòng ARM Cortex bao gồm ba cấu hình khác nhau của kiến trúc ARMv7:
    -Cấu hình A cho các ứng dụng tinh vi, yêu cầu cao chạy trên các hệ điều hành mở và phức tạp như Linux, Android…;
    -Cấu hình R dành cho các hệ thống thời gian thực và
    -Cấu hình M được tối ưu cho các ứng dụng vi điều khiển, cần tiết kiệm chi phí.

    Bộ vi xử lý Cortex-M3 là bộ vi xử lý ARM đầu tiên dựa trên kiến trúc ARMv7-M và được thiết kế đặc biệt để đạt được hiệu suất cao trong các ứng dụng nhúng cần tiết kiệm năng lượng và chi phí. Để đạt được hiệu suất cao hơn, bộ vi xử lý có thể làm việc nhiều hơn hoặc làm việc thông minh hơn. Đẩy tần số hoạt động cao hơn có thể làm tăng hiệu suất nhưng cũng đi kèm với việc tiêu thụ năng lượng nhiều hơn và việc thiết kế cũng phức tạp hơn. Nói cách khác, cùng thực hiện những tác vụ đó nhưng bằng cách nâng cao hiệu quả tính toán trong khi vẫn hoạt động ở tần số thấp sẽ dẫn đến sự đơn giản hóa trong việc thiết kế và ít tốn năng lượng hơn.

    Trung tâm của bộ vi xử lý Cortex-M3 là một lõi có cấu trúc đường ống tiên tiến 3 tầng, dựa trên kiến trúc Harvard, kết hợp nhiều tính năng mới mạnh mẽ như suy đoán việc rẽ nhánh, phép nhân được thực thi trong một chu kỳ và phép chia được thực hiện bằng phần cứng tạo nên một hiệu năng vượt trội (điểm Dhrystone là 1,25 DMIPS/MHz). Bộ vi xử lý Cortex-M3 hỗ trợ kiến trúc tập lệnh Thumb-2, giúp nó hoạt động hiệu quả hơn 70% cho mỗi MHz so với một bộ vi xử lý ARM7TDMI-S thực thi với tập lệnh Thumb, và hiệu quả hơn 35% so với bộ xử lý ARM7TDMI-S thực thi với tập lệnh ARM.

    *Lõi Cortex-M3:
    -Lõi trung tâm Cortex-M3 dựa trên kiến trúc Harvard, được đặc trưng bằng sự tách biệt giữa vùng nhớ chứa dữ liệu và chương trình do đó có các bus riêng để truy cập. Đặc tính này khác với dòng ARM7 dựa trên kiến trúc Von Neumann sử dụng chung vùng nhớ để chứa dữ liệu và chương trình, do đó dùng chung bus cho việc truy xuất. Vì có thể đọc cùng lúc lệnh và dữ liệu từ bộ nhớ, bộ vi xử lý Cortex-M3 có thể thực hiện nhiều hoạt động song song, tăng tốc thực thi ứng dụng.

    Click image for larger version

Name:	armcortexm3processor.JPG
Views:	1
Size:	49.4 KB
ID:	1372560

    -Lõi Cortex có cấu trúc đường ống gồm 3 tầng: Instruction Fetch, Instruction Decode và Instruction Execute. Khi gặp một lệnh nhánh, tầng decode chứa một chỉ thị nạp lệnh suy đoán có thể dẫn đến việc thực thi nhanh hơn. Bộ xử lý nạp lệnh dự định rẽ nhánh trong giai đoạn giải mã. Sau đó, trong giai đoạn thực thi, việc rẽ nhánh được giải quyết và bộ vi xử lý sẽ phân tích xem đâu là lệnh thực thi kế tiếp. Nếu việc rẽ nhánh không được chọn thì lệnh tiếp theo đã sẵn sàng. Còn nếu việc rẽ nhánh được chọn thì lệnh rẽ nhánh đó cũng đã sẵn sàng ngay lập tức, hạn chế thời gian rỗi chỉ còn một chu kỳ.

    -Bộ vi xử lý Cortex-M3 là một bộ vi xử lý 32-bit, với độ rộng của đường dẫn dữ liệu 32 bit, các dải thanh ghi và giao tiếp bộ nhớ. Có 13 thanh ghi đa dụng, hai con trỏ ngăn xếp, một thanh ghi liên kết, một bộ đếm chương trình và một số thanh ghi đặc biệt trong đó có một thanh ghi trạng thái chương trình.

    -Bộ vi xử lý Cortex-M3 hỗ trợ hai chế độ hoạt động (Thread và Handler) và hai mức truy cập tài nguyên của lõi xử lí (đặc quyền và không đặc quyền), tạo điều kiện cho việc cài đặt các hệ thống mở và phức tạp nhưng vẫn bảo mật. Những dòng mã không đặc quyền bị giới hạn hoặc không cho phép truy cập vào một số tài nguyên quan trọng (một số lệnh đặc biệt và các vùng nhớ nhất định).
    +Chế độ Thread là chế độ hoạt động tiêu biểu hỗ trợ cả mã đặc quyền và không đặc quyền.
    +Bộ vi xử lý sẽ vào chế độ Handler khi một ngoại lệ (exception) xảy ra và tất cả các mã là đặc quyền trong chế độ này.

    - Khả năng địa chỉ hóa 2^32=4gb địa chỉ: các địa chỉ định nghĩa sẵn, dành riêng cho mã lệnh (vùng mã lệnh), SRAM (vùng nhớ), bộ nhớ/thiết bị bên ngoài, thiết bị ngoại vi bên trong và bên ngoài. Ngoài ra còn có một vùng nhớ đặc biệt dành riêng cho nhà cung cấp.
    Click image for larger version

Name:	memmap.JPG
Views:	1
Size:	67.2 KB
ID:	1372561

    - NVIC (Nested Vectored Interrupt Controller) là thành phần tích hợp của bộ vi xử lý Cortex-M3 có khả năng xử lý ngắt rất linh hoạt và nhanh chóng. Trong cài đặt chuẩn, nó cung cấp một NMI (Non-Maskable Interrupt) và 32 ngắt vật lý đa dụng với 8 mức ưu tiên pre-emption. Nó có thể được cấu hình từ 1 đến 240 ngắt vật lý với tối đa 256 mức độ ưu tiên. Bộ vi xử lý Cortex-M3 sử dụng một bảng vector có thể tái định vị được, dùng để chứa địa chỉ của hàm xử lý ngắt. Khi nhận một ngắt, bộ xử lý sẽ lấy địa chỉ từ bảng vector thông qua bus chương trình. Bảng vector ngắt được đặt ở địa chỉ 0 khi reset, nhưng có thể được di chyển đến vị trí khác bằng cách lập trình một thanh ghi điều khiển


    Đôi khi chúng ta quan niệm nhầm về cái tên Cortex M3. Cortex M3 không phải là một vi điều khiển cụ thể, nó là tên một lõi vi xử lý của arm được đăng ký bản quyền. Các nhà sản xuất mua lõi này và thêm vào các ngoại vi sau đó đóng vỏ thành các vi điều khiển cụ thể. Chính vì vậy có rất nhiều các chip cụ thể của dòng arm Cortex M3 như chip của NXP LPC(LPC1768,..), của STMicroelectronics Stm32f(stm32f103c8t6,...) việc tìm hiểu chính là học việc sử dụng các ngoại vi của chip. Thực ra với người sử dụng, sau khi biết được sức mạnh và khả năng của lõi thì cái họ quan tâm là ngoại vi, việc chọn chip quyết định nhiều bởi ngoại vi trên nó. Các ngoại vi trên chip của các hãng có cách cấu hình và sử dụng rất khác nhau, chính vì vậy tuy có cũng lõi nhưng một chương trình ko thể nạp trên các chip khác nhau được. Việc tìm hiểu lõi giờ đây ít có ý nghĩa thay vào đó là việc học cách sử dụng ngoại vi.

    Thôi. Muộn quá. Để mai tiếp vậy. Mong các bác ủng hộ em.
    Last edited by vuxuansyhut; 13-01-2013, 02:13.

    Giải pháp điện tử của bạn

    Comment


    • #3
      Xin chào tất cả các bác. Một ngày chủ nhật bận rộn.
      Tiếp tục với Arm cortex M3.
      Không như cách tiếp cận với các loại vi điều khiển 8bit, việc tìm hiểu và học lập trình cho Arm Cortex M3(CM3) thường gắn liền với 2 "bí kíp" gối đầu giường đó là 2 tài liệu
      - Datasheet
      - Reference manual (Rất quan trọng)

      Datasheet : cung cấp cho ta cái nhìn tổng quan về chip, về ngoại vi, về các chân,... mà không đi sâu cụ thể về ngoại vi nào. Ta thường dùng tài liệu này để biết công lực của chip (khả năng và các ngoại vi hỗ trợ), đặc tính điện học, một số cấu hình phần cứng thiết kế mạch, xác định vị trí các pin, tra cứu sự liên kết giữa các ngoại vi trong chip và lõi (khá quan trọng). Từ đó giúp ta định hướng cấu hình ngoại vi bằng phần mềm một cách logic không máy móc.
      vd như với lpc1768
      Click image for larger version

Name:	lcp1768.jpg
Views:	1
Size:	175.5 KB
ID:	1372605
      nhìn trên sơ đồ, tất cả mọi thứ của chip hiện ra một cách rõ ràng và trực quan. Vì vậy theo ý kiến cá nhân của em, trước khi tìm hiểu một loại chip nào đó nên tìm hiểu sơ đồ khối của nó trước tiên.

      Reference manual : Tài liệu này hướng dẫn chi tiết cho ta cách cấu hình và sử dụng các modun, ngoại vi. Tài liệu này được viết bằng tiếng anh, là tài liệu đầy đủ nhất. Tuy viết bằng tiếng anh nhưng khá dễ dàng đọc cho anh em do toàn những từ mà ta có thể "đoán" được nghĩa . Tài liệu này rất dài, chúng ta chỉ nên lựa chọn đọc những phần quan tâm, khó có thể đủ thời gian và kiên nhẫn để đọc hết đám tài liệu này. Thường tài liệu này có phần "document map" ngay bên cạnh giúp ta nhanh chóng tìm được phần thông tin cần thiết.

      Xin chia sẻ 2 tài liệu này của LPC1768 tới anh em.
      LPC1769_68_67_66_65_64_63.pdf
      lpc1768 user manual.pdf

      - Trình biên dịch (Compiler): Keil arm là sự lựa chọn hàng đầu khi lập trình cho arm. Giao diện thân thiện dễ sử dụng, hỗ trợ rất nhiều chip và quan trọng là rất dễ tải và kiếm thuốc.

      Học thì phải đi đôi với hành. Đó là điều quan trọng nhất. Chúng ta nên đầu tư công cụ để học lập trình. Với người mới tiếp cận thì các kít phát triển với các modun liên kết ngoại vi đa dạng là sự lựa chọn tốt nhất. Các kit này trên thị trường khá sẵn. Ví dụ như kít lpc1768 của anh "trung của" sau đây
      Click image for larger version

Name:	IMG_0157.jpg
Views:	1
Size:	104.5 KB
ID:	1372610

      - Vấn đề nạp chương trình:
      + Hầu hết các chip arm hiện nay đều hỗ trợ nạp chương trình qua bootloader mà phổ biến là qua cổng Com. Cách nạp này khá thuận lợi nhưng còn 1 số tồn tại: không có khả năng debug, tốc độ nạp thấp (cổng com mà), phải dành riêng một ngoại vi cho việc nạp chương trình, khá đồ sộ, cần thao tác set jump trước khi nạp, đôi khi khó khăn trong việc tìm và sử dụng phần mềm nạp phù hợp.
      + Nếu có điều kiện ta nên sắm 1 bộ nạp đa năng như j link hoặc u link với "công lực" thâm hậu. Như với Jlink V8 có khả năng nạp và debug hầu hết các loại chip ARM như ARM7/9/11,Cortex-A5/A8/A9, Cortex-M0/M1/M3/M4/R4 hỗ trợ cả Jtag và SWD với tốc độ cao. Ulink có công lực cao hơn cả jlink (thấy thiên hạ đồn vậy chứ em chưa dùng ulink nên không rõ). Hiện tại em đang dùng 1 bản jlink v8 clone mua tại Hoàng Phát, khá ưng ý với sản phẩm này

      Click image for larger version

Name:	thsgroup jlink v8.JPG
Views:	1
Size:	29.9 KB
ID:	1372614

      Hiện tại có 2 chuẩn nạp phổ biến đó là Jtag và swd. Không có sự so sánh hơn kém cụ thể giữa 2 chuẩn nạp này nhưng ý kiến cá nhân của em thích chuẩn swd hơn do ít đường kết nối hơn.

      Sau đây em sẽ chuyển sang phần lập trình ứng dụng trên LPC1768. Em sử dụng kít LPC1768 như trên hình để chạy kiểm tra code.
      Last edited by vuxuansyhut; 14-01-2013, 00:47.

      Giải pháp điện tử của bạn

      Comment


      • #4
        2- Lập trình ứng dụng trên LPC1768
        Lpc1768 chỉ là một ví dụ em đưa ra để đưa ra cách lập trình với arm cortex M3. Việc sử dụng dòng chíp cụ thể nào là tùy điều kiện cá nhân có thể của st, có thể của nxp Đến một lúc nào đó ta sẽ nhận ra sự tương đồng giữa các dòng chíp này.
        2.1. Clock

        Bắt đầu lật bí kíp
        Xung clock có vai trò với vi điều khiển cũng như trái tim của con người vậy. Tất cả hoạt động của chip đều được giữ nhịp thông qua xung clock.
        Trong trang số 29 của tài liệu user manual có cung cấp sơ đồ khối của khâu tạo xung clock
        Click image for larger version

Name:	clock.jpg
Views:	1
Size:	54.6 KB
ID:	1372615

        Nhìn vào sơ đồ ta có thể thấy nguồn xung clock đầu vào có thể lấy thông qua 3 đường
        - osc_clk : thạch anh ngoài
        - rtc_clk : xung đồng hồ thời gian thực
        - irc_osc : bộ dao động nội

        để đạt được nguồn clock tần số cao và ổn định ta thường chọn nguồn xung từ thạch anh ngoài (osc_clk)

        Quan sát trong sơ đồ ta có thể thấy các khối nhân tần số (PLL) và các khối chia tần số. Việc thiết lập thông số phù hợp sẽ tạo được tần số mong muốn. Với LPC1768 tần số max đầu ra cclk là 100MHz tương ứng với tốc độ 125 DMIPS.

        Bộ PLL1 được sử dụng riêng để tạo tần số phục vụ giao tiếp usb.
        Nhìn vào sơ đồ ta có thể định hướng việc tao ra xung clock chung của hệ thống. Ví dụ như ta muốn tạo ra tần số cclk=100MHz với tần số đầu vào là thạch anh 12Mhz.
        Bộ PLL0 và "cpu clock divider" được sử dụng.
        Việc sử dụng bộ nhân tần số với những ai đã từng làm việc với pic thì không có gì xa lạ. Khi nhân tần số sẽ có những giới hạn về tần số max mà ta phải tuân thủ. Với arm cũng vậy. Trang 35 tài liệu "user manual" có cung cấp thông tin PLL0: Input (32 kHZ to 50 MHz), hệ số nhân (6 to 512), Output (275 MHz to 550 ).
        tại trang 36 :
        Click image for larger version

Name:	clock pll0.jpg
Views:	1
Size:	45.5 KB
ID:	1372617
        F_cco0 = (2 * M * F_in) / N
        nhận thấy ((12*100)/6)/2=100
        M=100, N=6 là kết quả cần tìm
        Sau khi tao ra pllclk, xung clock tiếp tục được chia nhỏ và đưa tới các ngoại vi.

        Giải pháp điện tử của bạn

        Comment


        • #5
          Ui. Những ngày bận rộn. Hic
          Chúng ta lại tiếp tục nhé. Tiến độ chậm quá
          Qua sơ đồ khối ta có thể biết được các nguồn xung clock cấp đến các modul và ngoại vi. Nguồn xung clock chủ yếu được cấp từ thạch anh ngoài, vì vậy việc lựa chọn giá trị cho thạch anh này ảnh hưởng tới sai số trong truyền thông.
          - Nếu ta viết project giao tiếp 232 nên chọn thạch anh sao cho sau khi nhân chia có thể tạo ra tốc độ chính xác, giảm thiểu sai số
          - Nếu ta viết project giao tiếp usb nên chọn thạch anh có giá trị chẵn để có thể tao ra clock 48Mhz.

          clock sau khi qua "CPU Clock Divider" tạo ra cclk,cclk1,cclk2,cclk4,cclk8 cung cấp tới lõi xử lý và các ngoại vi.

          Công việc đầu tiên trước khi lập trình đó là cấu hình nguồn phát xung clock.

          Code:
          /**************************************************************************//**
           * @file     system_LPC17xx.c
           * @brief    CMSIS Cortex-M3 Device Peripheral Access Layer Source File
           *           for the NXP LPC17xx Device Series
           * @version  V1.03
           * @date     07. October 2009
           *
           * [MENTION=238014]note[/MENTION]
           * Copyright (C) 2009 ARM Limited. All rights reserved.
           *
           * @par
           * ARM Limited (ARM) is supplying this software for use with Cortex-M 
           * processor based microcontrollers.  This file can be freely distributed 
           * within development tools that are supporting such ARM based processors. 
           *
           * @par
           * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
           * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
           * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
           * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
           * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
           *
           ******************************************************************************/
          
          
          #include <stdint.h>
          #include "LPC17xx.h"
          
          /*
          //-------- <<< Use Configuration Wizard in Context Menu >>> ------------------
          */
          
          /*--------------------- Clock Configuration ----------------------------------
          //
          // <e> Clock Configuration
          //   <h> System Controls and Status Register (SCS)
          //     <o1.4>    OSCRANGE: Main Oscillator Range Select
          //                     <0=>  1 MHz to 20 MHz
          //                     <1=> 15 MHz to 24 MHz
          //     <e1.5>       OSCEN: Main Oscillator Enable
          //     </e>
          //   </h>
          //
          //   <h> Clock Source Select Register (CLKSRCSEL)
          //     <o2.0..1>   CLKSRC: PLL Clock Source Selection
          //                     <0=> Internal RC oscillator
          //                     <1=> Main oscillator
          //                     <2=> RTC oscillator
          //   </h>
          //
          //   <e3> PLL0 Configuration (Main PLL)
          //     <h> PLL0 Configuration Register (PLL0CFG)
          //                     <i> F_cco0 = (2 * M * F_in) / N
          //                     <i> F_in must be in the range of 32 kHz to 50 MHz
          //                     <i> F_cco0 must be in the range of 275 MHz to 550 MHz
          //       <o4.0..14>  MSEL: PLL Multiplier Selection
          //                     <6-32768><#-1>
          //                     <i> M Value
          //       <o4.16..23> NSEL: PLL Divider Selection
          //                     <1-256><#-1>
          //                     <i> N Value
          //     </h>
          //   </e>
          //
          //   <e5> PLL1 Configuration (USB PLL)
          //     <h> PLL1 Configuration Register (PLL1CFG)
          //                     <i> F_usb = M * F_osc or F_usb = F_cco1 / (2 * P)
          //                     <i> F_cco1 = F_osc * M * 2 * P
          //                     <i> F_cco1 must be in the range of 156 MHz to 320 MHz
          //       <o6.0..4>   MSEL: PLL Multiplier Selection
          //                     <1-32><#-1>
          //                     <i> M Value (for USB maximum value is 4)
          //       <o6.5..6>   PSEL: PLL Divider Selection
          //                     <0=> 1
          //                     <1=> 2
          //                     <2=> 4
          //                     <3=> 8
          //                     <i> P Value
          //     </h>
          //   </e>
          //
          //   <h> CPU Clock Configuration Register (CCLKCFG)
          //     <o7.0..7>  CCLKSEL: Divide Value for CPU Clock from PLL0
          //                     <3-256><#-1>
          //   </h>
          //
          //   <h> USB Clock Configuration Register (USBCLKCFG)
          //     <o8.0..3>   USBSEL: Divide Value for USB Clock from PLL0
          //                     <0-15>
          //                     <i> Divide is USBSEL + 1
          //   </h>
          //
          //   <h> Peripheral Clock Selection Register 0 (PCLKSEL0)
          //     <o9.0..1>    PCLK_WDT: Peripheral Clock Selection for WDT
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.2..3>    PCLK_TIMER0: Peripheral Clock Selection for TIMER0
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.4..5>    PCLK_TIMER1: Peripheral Clock Selection for TIMER1
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.6..7>    PCLK_UART0: Peripheral Clock Selection for UART0
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.8..9>    PCLK_UART1: Peripheral Clock Selection for UART1
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.12..13>  PCLK_PWM1: Peripheral Clock Selection for PWM1
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.14..15>  PCLK_I2C0: Peripheral Clock Selection for I2C0
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.16..17>  PCLK_SPI: Peripheral Clock Selection for SPI
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.20..21>  PCLK_SSP1: Peripheral Clock Selection for SSP1
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.22..23>  PCLK_DAC: Peripheral Clock Selection for DAC
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.24..25>  PCLK_ADC: Peripheral Clock Selection for ADC
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o9.26..27>  PCLK_CAN1: Peripheral Clock Selection for CAN1
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 6
          //     <o9.28..29>  PCLK_CAN2: Peripheral Clock Selection for CAN2
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 6
          //     <o9.30..31>  PCLK_ACF: Peripheral Clock Selection for ACF
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 6
          //   </h>
          //
          //   <h> Peripheral Clock Selection Register 1 (PCLKSEL1)
          //     <o10.0..1>   PCLK_QEI: Peripheral Clock Selection for the Quadrature Encoder Interface
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.2..3>   PCLK_GPIO: Peripheral Clock Selection for GPIOs
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.4..5>   PCLK_PCB: Peripheral Clock Selection for the Pin Connect Block
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.6..7>   PCLK_I2C1: Peripheral Clock Selection for I2C1
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.10..11> PCLK_SSP0: Peripheral Clock Selection for SSP0
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.12..13> PCLK_TIMER2: Peripheral Clock Selection for TIMER2
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.14..15> PCLK_TIMER3: Peripheral Clock Selection for TIMER3
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.16..17> PCLK_UART2: Peripheral Clock Selection for UART2
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.18..19> PCLK_UART3: Peripheral Clock Selection for UART3
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.20..21> PCLK_I2C2: Peripheral Clock Selection for I2C2
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.22..23> PCLK_I2S: Peripheral Clock Selection for I2S
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.26..27> PCLK_RIT: Peripheral Clock Selection for the Repetitive Interrupt Timer
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.28..29> PCLK_SYSCON: Peripheral Clock Selection for the System Control Block
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //     <o10.30..31> PCLK_MC: Peripheral Clock Selection for the Motor Control PWM
          //                     <0=> Pclk = Cclk / 4
          //                     <1=> Pclk = Cclk
          //                     <2=> Pclk = Cclk / 2
          //                     <3=> Pclk = Hclk / 8
          //   </h>
          //
          //   <h> Power Control for Peripherals Register (PCONP)
          //     <o11.1>      PCTIM0: Timer/Counter 0 power/clock enable
          //     <o11.2>      PCTIM1: Timer/Counter 1 power/clock enable
          //     <o11.3>      PCUART0: UART 0 power/clock enable
          //     <o11.4>      PCUART1: UART 1 power/clock enable
          //     <o11.6>      PCPWM1: PWM 1 power/clock enable
          //     <o11.7>      PCI2C0: I2C interface 0 power/clock enable
          //     <o11.8>      PCSPI: SPI interface power/clock enable
          //     <o11.9>      PCRTC: RTC power/clock enable
          //     <o11.10>     PCSSP1: SSP interface 1 power/clock enable
          //     <o11.12>     PCAD: A/D converter power/clock enable
          //     <o11.13>     PCCAN1: CAN controller 1 power/clock enable
          //     <o11.14>     PCCAN2: CAN controller 2 power/clock enable
          //     <o11.15>     PCGPIO: GPIOs power/clock enable
          //     <o11.16>     PCRIT: Repetitive interrupt timer power/clock enable
          //     <o11.17>     PCMC: Motor control PWM power/clock enable
          //     <o11.18>     PCQEI: Quadrature encoder interface power/clock enable
          //     <o11.19>     PCI2C1: I2C interface 1 power/clock enable
          //     <o11.21>     PCSSP0: SSP interface 0 power/clock enable
          //     <o11.22>     PCTIM2: Timer 2 power/clock enable
          //     <o11.23>     PCTIM3: Timer 3 power/clock enable
          //     <o11.24>     PCUART2: UART 2 power/clock enable
          //     <o11.25>     PCUART3: UART 3 power/clock enable
          //     <o11.26>     PCI2C2: I2C interface 2 power/clock enable
          //     <o11.27>     PCI2S: I2S interface power/clock enable
          //     <o11.29>     PCGPDMA: GP DMA function power/clock enable
          //     <o11.30>     PCENET: Ethernet block power/clock enable
          //     <o11.31>     PCUSB: USB interface power/clock enable
          //   </h>
          //
          //   <h> Clock Output Configuration Register (CLKOUTCFG)
          //     <o12.0..3>   CLKOUTSEL: Selects clock source for CLKOUT
          //                     <0=> CPU clock
          //                     <1=> Main oscillator
          //                     <2=> Internal RC oscillator
          //                     <3=> USB clock
          //                     <4=> RTC oscillator
          //     <o12.4..7>   CLKOUTDIV: Selects clock divider for CLKOUT
          //                     <1-16><#-1>
          //     <o12.8>      CLKOUT_EN: CLKOUT enable control
          //   </h>
          //
          // </e>
          */
          #define CLOCK_SETUP           1
          #define SCS_Val               0x00000020
          #define CLKSRCSEL_Val         0x00000001
          #define PLL0_SETUP            1
          #define PLL0CFG_Val           0x00050063
          #define PLL1_SETUP            1
          #define PLL1CFG_Val           0x00000023
          #define CCLKCFG_Val           0x00000003
          #define USBCLKCFG_Val         0x00000000
          #define PCLKSEL0_Val          0x00000000
          #define PCLKSEL1_Val          0x00000000
          #define PCONP_Val             0x042887DE
          #define CLKOUTCFG_Val         0x00000000
          
          
          /*--------------------- Flash Accelerator Configuration ----------------------
          //
          // <e> Flash Accelerator Configuration
          //   <o1.0..1>   FETCHCFG: Fetch Configuration
          //               <0=> Instruction fetches from flash are not buffered
          //               <1=> One buffer is used for all instruction fetch buffering
          //               <2=> All buffers may be used for instruction fetch buffering
          //               <3=> Reserved (do not use this setting)
          //   <o1.2..3>   DATACFG: Data Configuration
          //               <0=> Data accesses from flash are not buffered
          //               <1=> One buffer is used for all data access buffering
          //               <2=> All buffers may be used for data access buffering
          //               <3=> Reserved (do not use this setting)
          //   <o1.4>      ACCEL: Acceleration Enable
          //   <o1.5>      PREFEN: Prefetch Enable
          //   <o1.6>      PREFOVR: Prefetch Override
          //   <o1.12..15> FLASHTIM: Flash Access Time
          //               <0=> 1 CPU clock (for CPU clock up to 20 MHz)
          //               <1=> 2 CPU clocks (for CPU clock up to 40 MHz)
          //               <2=> 3 CPU clocks (for CPU clock up to 60 MHz)
          //               <3=> 4 CPU clocks (for CPU clock up to 80 MHz)
          //               <4=> 5 CPU clocks (for CPU clock up to 100 MHz)
          //               <5=> 6 CPU clocks (for any CPU clock)
          // </e>
          */
          #define FLASH_SETUP           1
          #define FLASHCFG_Val          0x0000303A
          
          /*
          //-------- <<< end of configuration section >>> ------------------------------
          */
          
          /*----------------------------------------------------------------------------
            Check the register settings
           *----------------------------------------------------------------------------*/
          #define CHECK_RANGE(val, min, max)                ((val < min) || (val > max))
          #define CHECK_RSVD(val, mask)                     (val & mask)
          
          /* Clock Configuration -------------------------------------------------------*/
          #if (CHECK_RSVD((SCS_Val),       ~0x00000030))
             #error "SCS: Invalid values of reserved bits!"
          #endif
          
          #if (CHECK_RANGE((CLKSRCSEL_Val), 0, 2))
             #error "CLKSRCSEL: Value out of range!"
          #endif
          
          #if (CHECK_RSVD((PLL0CFG_Val),   ~0x00FF7FFF))
             #error "PLL0CFG: Invalid values of reserved bits!"
          #endif
          
          #if (CHECK_RSVD((PLL1CFG_Val),   ~0x0000007F))
             #error "PLL1CFG: Invalid values of reserved bits!"
          #endif
          
          #if ((CCLKCFG_Val != 0) && (((CCLKCFG_Val - 1) % 2)))
             #error "CCLKCFG: CCLKSEL field does not contain only odd values or 0!"
          #endif
          
          #if (CHECK_RSVD((USBCLKCFG_Val), ~0x0000000F))
             #error "USBCLKCFG: Invalid values of reserved bits!"
          #endif
          
          #if (CHECK_RSVD((PCLKSEL0_Val),   0x000C0C00))
             #error "PCLKSEL0: Invalid values of reserved bits!"
          #endif
          
          #if (CHECK_RSVD((PCLKSEL1_Val),   0x03000300))
             #error "PCLKSEL1: Invalid values of reserved bits!"
          #endif
          
          #if (CHECK_RSVD((PCONP_Val),      0x10100821))
             #error "PCONP: Invalid values of reserved bits!"
          #endif
          
          #if (CHECK_RSVD((CLKOUTCFG_Val), ~0x000001FF))
             #error "CLKOUTCFG: Invalid values of reserved bits!"
          #endif
          
          /* Flash Accelerator Configuration -------------------------------------------*/
          #if (CHECK_RSVD((FLASHCFG_Val), ~0x0000F07F))
             #error "FLASHCFG: Invalid values of reserved bits!"
          #endif
          
          
          /*----------------------------------------------------------------------------
            DEFINES
           *----------------------------------------------------------------------------*/
              
          /*----------------------------------------------------------------------------
            Define clocks
           *----------------------------------------------------------------------------*/
          #define XTAL        (12000000UL)        /* Oscillator frequency               */
          #define OSC_CLK     (      XTAL)        /* Main oscillator frequency          */
          #define RTC_CLK     (   32000UL)        /* RTC oscillator frequency           */
          #define IRC_OSC     ( 4000000UL)        /* Internal RC oscillator frequency   */
          
          
          /* F_cco0 = (2 * M * F_in) / N  */
          #define __M               (((PLL0CFG_Val      ) & 0x7FFF) + 1)
          #define __N               (((PLL0CFG_Val >> 16) & 0x00FF) + 1)
          #define __FCCO(__F_IN)    ((2 * __M * __F_IN) / __N) 
          #define __CCLK_DIV        (((CCLKCFG_Val      ) & 0x00FF) + 1)
          
          /* Determine core clock frequency according to settings */
           #if (PLL0_SETUP)
              #if   ((CLKSRCSEL_Val & 0x03) == 1)
                  #define __CORE_CLK (__FCCO(OSC_CLK) / __CCLK_DIV)
              #elif ((CLKSRCSEL_Val & 0x03) == 2)
                  #define __CORE_CLK (__FCCO(RTC_CLK) / __CCLK_DIV)
              #else 
                  #define __CORE_CLK (__FCCO(IRC_OSC) / __CCLK_DIV)
              #endif
           #else
              #if   ((CLKSRCSEL_Val & 0x03) == 1)
                  #define __CORE_CLK (OSC_CLK         / __CCLK_DIV)
              #elif ((CLKSRCSEL_Val & 0x03) == 2)
                  #define __CORE_CLK (RTC_CLK         / __CCLK_DIV)
              #else
                  #define __CORE_CLK (IRC_OSC         / __CCLK_DIV)
              #endif
           #endif
          
          
          /*----------------------------------------------------------------------------
            Clock Variable definitions
           *----------------------------------------------------------------------------*/
          uint32_t SystemCoreClock = __CORE_CLK;/*!< System Clock Frequency (Core Clock)*/
          
          
          /*----------------------------------------------------------------------------
            Clock functions
           *----------------------------------------------------------------------------*/
          void SystemCoreClockUpdate (void)            /* Get Core Clock Frequency      */
          {
            /* Determine clock frequency according to clock register values             */
            if (((LPC_SC->PLL0STAT >> 24) & 3) == 3) { /* If PLL0 enabled and connected */
              switch (LPC_SC->CLKSRCSEL & 0x03) {
                case 0:                                /* Int. RC oscillator => PLL0    */
                case 3:                                /* Reserved, default to Int. RC  */
                  SystemCoreClock = (IRC_OSC * 
                                    ((2 * ((LPC_SC->PLL0STAT & 0x7FFF) + 1)))  /
                                    (((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1)    /
                                    ((LPC_SC->CCLKCFG & 0xFF)+ 1));
                  break;
                case 1:                                /* Main oscillator => PLL0       */
                  SystemCoreClock = (OSC_CLK * 
                                    ((2 * ((LPC_SC->PLL0STAT & 0x7FFF) + 1)))  /
                                    (((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1)    /
                                    ((LPC_SC->CCLKCFG & 0xFF)+ 1));
                  break;
                case 2:                                /* RTC oscillator => PLL0        */
                  SystemCoreClock = (RTC_CLK * 
                                    ((2 * ((LPC_SC->PLL0STAT & 0x7FFF) + 1)))  /
                                    (((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1)    /
                                    ((LPC_SC->CCLKCFG & 0xFF)+ 1));
                  break;
              }
            } else {
              switch (LPC_SC->CLKSRCSEL & 0x03) {
                case 0:                                /* Int. RC oscillator => PLL0    */
                case 3:                                /* Reserved, default to Int. RC  */
                  SystemCoreClock = IRC_OSC / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
                  break;
                case 1:                                /* Main oscillator => PLL0       */
                  SystemCoreClock = OSC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
                  break;
                case 2:                                /* RTC oscillator => PLL0        */
                  SystemCoreClock = RTC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1);
                  break;
              }
            }
          
          }
          
          /**
           * Initialize the system
           *
           * @param  none
           * @return none
           *
           * @brief  Setup the microcontroller system.
           *         Initialize the System.
           */
          void SystemInit (void)
          {
          #if (CLOCK_SETUP)                       /* Clock Setup                        */
            LPC_SC->SCS       = SCS_Val;
            if (SCS_Val & (1 << 5)) {             /* If Main Oscillator is enabled      */
              while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready    */
            }
          
            LPC_SC->CCLKCFG   = CCLKCFG_Val;      /* Setup Clock Divider                */
          
          #if (PLL0_SETUP)
            LPC_SC->CLKSRCSEL = CLKSRCSEL_Val;    /* Select Clock Source for PLL0       */
          
            LPC_SC->PLL0CFG   = PLL0CFG_Val;      /* configure PLL0                     */
            LPC_SC->PLL0FEED  = 0xAA;
            LPC_SC->PLL0FEED  = 0x55;
          
            LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                        */
            LPC_SC->PLL0FEED  = 0xAA;
            LPC_SC->PLL0FEED  = 0x55;
            while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0                    */
          
            LPC_SC->PLL0CON   = 0x03;             /* PLL0 Enable & Connect              */
            LPC_SC->PLL0FEED  = 0xAA;
            LPC_SC->PLL0FEED  = 0x55;
            while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));/* Wait for PLLC0_STAT & PLLE0_STAT */
          #endif
          
          #if (PLL1_SETUP)
            LPC_SC->PLL1CFG   = PLL1CFG_Val;
            LPC_SC->PLL1FEED  = 0xAA;
            LPC_SC->PLL1FEED  = 0x55;
          
            LPC_SC->PLL1CON   = 0x01;             /* PLL1 Enable                        */
            LPC_SC->PLL1FEED  = 0xAA;
            LPC_SC->PLL1FEED  = 0x55;
            while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1                    */
          
            LPC_SC->PLL1CON   = 0x03;             /* PLL1 Enable & Connect              */
            LPC_SC->PLL1FEED  = 0xAA;
            LPC_SC->PLL1FEED  = 0x55;
            while (!(LPC_SC->PLL1STAT & ((1<< 9) | (1<< 8))));/* Wait for PLLC1_STAT & PLLE1_STAT */
          #else
            LPC_SC->USBCLKCFG = USBCLKCFG_Val;    /* Setup USB Clock Divider            */
          #endif
          
            LPC_SC->PCLKSEL0  = PCLKSEL0_Val;     /* Peripheral Clock Selection         */
            LPC_SC->PCLKSEL1  = PCLKSEL1_Val;
          
            LPC_SC->PCONP     = PCONP_Val;        /* Power Control for Peripherals      */
          
            LPC_SC->CLKOUTCFG = CLKOUTCFG_Val;    /* Clock Output Configuration         */
          #endif
          
          #if (FLASH_SETUP == 1)                  /* Flash Accelerator Setup            */
            LPC_SC->FLASHCFG  = FLASHCFG_Val;
          #endif
          }

          Giải pháp điện tử của bạn

          Comment


          • #6
            Mong bác tiếp tục chia sẻ để những người mới dễ tiếp cận với ARM,cảm ơn tình thần của bác

            Comment


            • #7
              Chào buổi sáng! Chúc các bác một ngày tốt lành.
              Trong code trên có đưa ra hàm void SystemInit(void). Hàm này được gọi đầu chương trình main() để cấu hình nguồn xung clock cho lõi và các ngoại vi trong chip. Với chip ST và bộ thư viện chuẩn, hàm này được gọi một cách tự động trong file startup.s, còn với LPC chúng ta cần gọi hàm này.

              Trong hàm chia ra các phần rõ rệt xoay quanh các vấn đề sau
              - lựa chọn nguồn xung clock đầu vào
              - cấu hình bộ PLL0 tạo pllclk cấp
              - cấu hình bộ PLL1 tạo xung cung cấp cho USB
              - cấu hình bộ watchdog

              thao tác cấu hình cho từng phần này tương đối giống nhau. Em chỉ xin giải thích chi tiết cấu hình cho bộ PLL0 và xung clock tới các ngoại vi tức pclk,pclk1,pclk2,pclk4,pclk8
              Code:
              #if (PLL0_SETUP)
                LPC_SC->CLKSRCSEL = CLKSRCSEL_Val;    /* Select Clock Source for PLL0       */
              
                LPC_SC->PLL0CFG   = PLL0CFG_Val;      /* configure PLL0                     */
                LPC_SC->PLL0FEED  = 0xAA;
                LPC_SC->PLL0FEED  = 0x55;
              
                LPC_SC->PLL0CON   = 0x01;             /* PLL0 Enable                        */
                LPC_SC->PLL0FEED  = 0xAA;
                LPC_SC->PLL0FEED  = 0x55;
                while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0                    */
              
                LPC_SC->PLL0CON   = 0x03;             /* PLL0 Enable & Connect              */
                LPC_SC->PLL0FEED  = 0xAA;
                LPC_SC->PLL0FEED  = 0x55;
                while (!(LPC_SC->PLL0STAT & ((1<<25) | (1<<24))));/* Wait for PLLC0_STAT & PLLE0_STAT */
              #endif
              - lựa chọn xung clock
              tại trang 34 user manual
              Click image for larger version

Name:	2.jpg
Views:	1
Size:	64.9 KB
ID:	1372789
              để chọn thạch anh ngoài CLKSRC=0x01

              tại trang 36 của tài liệu user manual
              Click image for larger version

Name:	1.jpg
Views:	1
Size:	235.7 KB
ID:	1372788
              nêu lên sơ đồ khối và 5 thanh ghi liên quan
              cấu hình cho khối này chính là đưa giá trị phù hợp vào 5 thành ghi này.

              Các giá trị M,N
              tại trang 37
              Click image for larger version

Name:	3.jpg
Views:	1
Size:	84.0 KB
ID:	1372790
              MSEL0 và NSEL0 lựa chọn giá trị M,N

              PLL0CON
              Click image for larger version

Name:	2.jpg
Views:	1
Size:	64.9 KB
ID:	1372789
              chỉ có 2 bit đầu tiên được quan tâm
              bit 0: Cho phép bộ PLL0 hoạt động
              bit 1: PLL0 conect

              cấu hình pclk,pclk1,pclk2,pclk4,pclk8
              Click image for larger version

Name:	4.jpg
Views:	1
Size:	105.6 KB
ID:	1372791
              Click image for larger version

Name:	5.jpg
Views:	1
Size:	104.4 KB
ID:	1372792

              Code:
              LPC_SC->PCLKSEL0  = PCLKSEL0_Val;     /* Peripheral Clock Selection         */
                LPC_SC->PCLKSEL1  = PCLKSEL1_Val;
              
                LPC_SC->PCONP     = PCONP_Val;        /* Power Control for Peripherals      */
              
                LPC_SC->CLKOUTCFG = CLKOUTCFG_Val;    /* Clock Output Configuration         */
              Khá dễ hiểu đúng không các bác.
              Last edited by vuxuansyhut; 17-01-2013, 10:13.

              Giải pháp điện tử của bạn

              Comment


              • #8
                sao lại không được up quá 5 file nhỉ ?
                Click image for larger version

Name:	6.jpg
Views:	1
Size:	35.8 KB
ID:	1372793

                Giải pháp điện tử của bạn

                Comment


                • #9
                  Hic. Quá lâu cho 1 bài viết. Về cuối năm bận quá các bác ah. Có em cứ up code lên rồi giải thích những chỗ cần thiết.
                  Hôm nay em sẽ chia sẻ phần GPIO. Gửi các bác code nháy led đơn giản của LPC1768
                  Code:
                  /**************************************************************************//**
                   * @file     main.c
                   * @brief    CMSIS Cortex-M3 GPIO example
                   *           a LED using CM3 SysTick
                   * @version  V1.30
                   * @date     24. Jan 2010
                   *
                   * [MENTION=238014]note[/MENTION]
                   * Copyright (C) 2009 ARM Limited. All rights reserved.
                   *
                   * @par
                   * ARM Limited (ARM) is supplying this software for use with Cortex-M 
                   * processor based microcontrollers.  This file can be freely distributed 
                   * within development tools that are supporting such ARM based processors. 
                   *
                   * @par
                   * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
                   * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
                   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
                   * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
                   * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
                   *
                   ******************************************************************************/
                  
                  #include "LPC17xx.h"
                  
                  
                  volatile uint32_t msTicks;                            /* counts 1ms timeTicks */
                  /*----------------------------------------------------------------------------
                    SysTick_Handler
                   *----------------------------------------------------------------------------*/
                  void SysTick_Handler(void) {
                    msTicks++;                        /* increment counter necessary in Delay() */
                  }
                  
                  /*------------------------------------------------------------------------------
                    delays number of tick Systicks (happens every 1 ms)
                   *------------------------------------------------------------------------------*/
                  __INLINE static void Delay (uint32_t dlyTicks) {
                    uint32_t curTicks;
                  
                    curTicks = msTicks;
                    while ((msTicks - curTicks) < dlyTicks);
                  }
                  
                  /*------------------------------------------------------------------------------
                    configer LED pins
                   *------------------------------------------------------------------------------*/
                  __INLINE static void LED_Config(void) {
                  
                    LPC_GPIO2->FIODIR = 0x000000ff;               /* LEDs PORT2 are Output */
                    LPC_GPIO0->FIODIR = 0x00200000; 
                    LPC_GPIO0->FIOPIN |=  0x00200000; 
                  }
                  
                  /*------------------------------------------------------------------------------
                    Switch on LEDs
                   *------------------------------------------------------------------------------*/
                  __INLINE static void LED_On (uint32_t led) {
                  
                    LPC_GPIO2->FIOPIN |=  (led);                  /* Turn On  LED */
                  }
                  
                  /*------------------------------------------------------------------------------
                    Switch off LEDs
                   *------------------------------------------------------------------------------*/
                  __INLINE static void LED_Off (uint32_t led) {
                  
                    LPC_GPIO2->FIOPIN &= ~(led);                  /* Turn Off LED */
                  }
                  
                  /*----------------------------------------------------------------------------
                    MAIN function
                   *----------------------------------------------------------------------------*/
                  int main (void) {
                    uint8_t  location;
                   	
                    if (SysTick_Config(SystemCoreClock / 1000)) { /* Setup SysTick Timer for 1 msec interrupts  */
                      while (1);                                  /* Capture error */
                    }
                    
                    LED_Config();                             
                   
                    while(1) 
                    {
                    	LED_On (0xff);
                  	Delay (500);
                  	LED_Off(0xff);
                    	for(location=0;location<8;location++)
                  	{
                      	LED_On ((1<<location));                     /* Turn on the LED. */
                      	Delay (100);                                /* delay  100 Msec */
                      	LED_Off ((1<<location));                    /* Turn off the LED. */
                      	Delay (100);                                /* delay  100 Msec */
                  	}
                    }
                    
                  }
                  GPIO.rar

                  Giải pháp điện tử của bạn

                  Comment


                  • #10
                    Cám ơn bạn đã chia sẻ nhiều kinh nghiệm. Trong đoạn code bạn gửi có hàm SysTick_Handler, không thấy có chỗ nào tham chiếu đến hàm này? Liệu đây có phải làm hàm xử lý ngắt không bạn nhỉ? Mình xin bổ sung một tài liệu sau đây: http://www.state-machine.com/arm/Bui...M_with_GNU.pdf, tài liệu này giới thiệu cách thức viết một chương trình sử dụng trình biên dịch GNU ARM, không sử dụng các IDE như Keil hay IAR. Chúng ta có thể không cần học theo cái đó làm sẽ vất vả nhưng chúng ta cần biết để làm chủ hoàn toàn các đoạn mã được sinh tự động trong các tools như startup code, linker script và make file.
                    Mình đưa ra một ví dụ cụ thể, ví dụ thông thường các bạn mới làm về vi điều khiển thường bỏ qua một file rất quan trọng trong các đoạn code đó là startup code (viết bằng mã Assembly). Chúng ta không cần phải hiểu ngay toàn bộ đoạn mã đó, nhưng chúng ta nên biết trong đoạn mã đó nó làm một số công việc quan trọng: thiết lập bảng vector ngắt -> khởi tạo mức thấp (xung nhịp đồng hồ....) -> khởi tạo các vùng nhớ cho các stack của 7 chế độ hoạt động của ARM(User/System, Supervisor, IRQ, FIQ, Undefined, ...) -> gọi hàm main.
                    --------------------------------------------------
                    Hệ thống đào tạo Lập trình nhúng ARM trên Linux

                    Email:

                    Comment


                    • #11
                      Nguyên văn bởi embedded247 Xem bài viết
                      Cám ơn bạn đã chia sẻ nhiều kinh nghiệm. Trong đoạn code bạn gửi có hàm SysTick_Handler, không thấy có chỗ nào tham chiếu đến hàm này? Liệu đây có phải làm hàm xử lý ngắt không bạn nhỉ? Mình xin bổ sung một tài liệu sau đây: http://www.state-machine.com/arm/Bui...M_with_GNU.pdf, tài liệu này giới thiệu cách thức viết một chương trình sử dụng trình biên dịch GNU ARM, không sử dụng các IDE như Keil hay IAR. Chúng ta có thể không cần học theo cái đó làm sẽ vất vả nhưng chúng ta cần biết để làm chủ hoàn toàn các đoạn mã được sinh tự động trong các tools như startup code, linker script và make file.
                      Mình đưa ra một ví dụ cụ thể, ví dụ thông thường các bạn mới làm về vi điều khiển thường bỏ qua một file rất quan trọng trong các đoạn code đó là startup code (viết bằng mã Assembly). Chúng ta không cần phải hiểu ngay toàn bộ đoạn mã đó, nhưng chúng ta nên biết trong đoạn mã đó nó làm một số công việc quan trọng: thiết lập bảng vector ngắt -> khởi tạo mức thấp (xung nhịp đồng hồ....) -> khởi tạo các vùng nhớ cho các stack của 7 chế độ hoạt động của ARM(User/System, Supervisor, IRQ, FIQ, Undefined, ...) -> gọi hàm main.
                      hàm bạn nhắc đến là hàm tạo ngắt hệ thống thường dùng cho xử lý đa nhiệm như kiểu hệ điều hành. Mình hay dùng cái này để tạo thời gian delay chính xác. Luồng này ít người quan tâm quá kể cũng hơi buồn. Mình muốn viết nhiều hơn nhưng phần vì cuối năm bận nhiều việc quá, phần vì ít bạn quan tâm. Dường như chip arm của nxp ko đủ sức hút với các bạn.
                      Đồng quan điểm với bạn về File startup, nó rất quan trọng. Ví dụ như ta muốn viết các hàm phục vụ ngắt thì cần tham khảo file này để biết khai báo tên hàm phục vụ ngắt.

                      Giải pháp điện tử của bạn

                      Comment


                      • #12
                        Ngay từ đầu mình thấy luồng của bạn rất hay và hoàn toàn ủng hộ (tất nhiên mới ủng hộ suông chứ chưa bằng bài viết đóng góp nào) nhưng một thời gian vẫn thấy chủ yếu một mình bạn. Vậy có lẽ do ARM của NXP không đủ sức hấp dẫn, ngay bản thân mình khi nghiên cứu về ARM mình cũng đã loại bỏ NXP do một số nguyên nhân:

                        - Chip không dễ mua ở VN
                        - Các board phát triển không đa dạng và cũng không dễ mua bằng các hãng khác
                        - Cái tên của nó khó đọc (NXP, LPC)

                        Thay vào đó mình chọn STM32 của ST:
                        - Chip rẻ hơn, dễ mua hơn
                        - Board phát triển có sẵn nhiều nơi cung cấp, các board discovery siêu rẻ có đủ từ M0 ~ M4
                        - Cái tên theo mình là đẹp và dễ đọc: STM32

                        Vài ý kiến cá nhân của mình là vậy.

                        Comment


                        • #13
                          Nguyên văn bởi itanium7000 Xem bài viết
                          Ngay từ đầu mình thấy luồng của bạn rất hay và hoàn toàn ủng hộ (tất nhiên mới ủng hộ suông chứ chưa bằng bài viết đóng góp nào) nhưng một thời gian vẫn thấy chủ yếu một mình bạn. Vậy có lẽ do ARM của NXP không đủ sức hấp dẫn, ngay bản thân mình khi nghiên cứu về ARM mình cũng đã loại bỏ NXP do một số nguyên nhân:

                          - Chip không dễ mua ở VN
                          - Các board phát triển không đa dạng và cũng không dễ mua bằng các hãng khác
                          - Cái tên của nó khó đọc (NXP, LPC)

                          Thay vào đó mình chọn STM32 của ST:
                          - Chip rẻ hơn, dễ mua hơn
                          - Board phát triển có sẵn nhiều nơi cung cấp, các board discovery siêu rẻ có đủ từ M0 ~ M4
                          - Cái tên theo mình là đẹp và dễ đọc: STM32

                          Vài ý kiến cá nhân của mình là vậy.
                          - stm32 cũng khó mua ở VN như lpc vậy.
                          - Board phát triển, cần quái gì cái thứ này ? nói chung chỉ sử dụng khi lười vẽ mạch, luời làm pcb mà thôi.
                          - Ông nào nói tên của stm32 dễ đọc và dễ nhớ thì ITX phải khen là rất có tải trong việc nhớ mấy thứ lăng nhăng.

                          @ vuxuansyhut : bài viết của em mới chỉ mới ở phần "hello world" vì vậy ít người quan tâm cũng là chính xác, vì nó rất đơn giản => hiểu theo nghĩa là nhiều người biết và cũng như em vậy, " Biết rồi đọc lại làm gì ?", hy vọng em sớm đi qua khỏi phần "hello world".
                          Trong box nhớ không lầm thì ITX đã post full code về tất cả các module của lpc1114 trên Keil, và Ulink thì được dientuvietnam.net phổ biến đầu tiên.

                          Nhưng đã làm việc với lpc thì Compiler nhiều người xài lại là Compiler LPCXpresso của Code Red thiết kế riêng cho LPC, rất ít người xài Compiler Keil. Bởi vì LPC và Compiler LPCXpresso là anh em một nhà, và cũng là thứ có giá trị nhất khi sử dụng chip LPC.

                          Tóm lại nếu nói so sánh 2 dòng ở VN thì:
                          - stm32: Ở VN có lợi điểm là giá mua lẻ ngang bằng giá mua sỉ => lợi thế giá rẻ ở số lượng thấp.
                          - LPC: Trình biên dịch (Compiler ) có sẵn, miễn phí ( cho LPC ) và mạnh mẽ.
                          Từ chối trách nhiệm:
                          Mọi thông tin từ ITX cung cấp với hi vọng nó có ích và không đi kèm với bất kì sự bảo đảm nào.
                          Blog: http://mritx.blogspot.com

                          Comment


                          • #14
                            khi đã đụng tới 32bit hoặc upper thì hầu như ít quan tâm tới phần cứng và chủ yếu tập trung vào software là chính.

                            Comment


                            • #15
                              Nguyên văn bởi vuxuansyhut Xem bài viết
                              Luồng này ít người quan tâm quá kể cũng hơi buồn. Mình muốn viết nhiều hơn nhưng phần vì cuối năm bận nhiều việc quá, phần vì ít bạn quan tâm. Dường như chip arm của nxp ko đủ sức hút với các bạn.
                              Xin chào bạn!

                              Mình nghĩ cũng chưa hẳn như bạn nghĩ. Mình cũng mới bắt đầu tìm hiểu về lập trình với dòng chíp ARM nên chưa biết gì để đóng góp bằng những việc làm như bạn. Mình rất ủng hộ tinh thần nhiệt tình của bạn.

                              Chip của NXP không hẳn là không mạnh so với các hãng khác. Cũng đều dựa trên lõi ARM thôi. Vấn đề là có sự khác nhau ở việc tìm kiếm chip, công cụ hỗ trợ nghiên cứu. Cái này ST có vẻ có lợi thế ở VN hơn cả.

                              Dùng chip nào thì cũng chỉ là công cụ phục vụ nghiên cứu, quan trọng là học được khả năng tư duy thiết kế cho các ứng dụng trong thực tế. Làm sao để sản phẩm ta làm ra là gì và hoạt động như thế nào, có đủ mạnh để cạnh tranh với sản phẩm nước ngoài không. Không đơn giản là chỉ vọc xong một bộ kit nào đó.

                              Nhưng cái gì cũng đều phải có sự khởi đầu. Bài viết của bạn có thể không thu hút được sự quan tâm của các cao thủ (vì họ đã giỏi rồi) nhưng sẽ rất có ích cho những người đang bắt đầu nghiên cứu về ARM.

                              Hy vọng bạn tiếp tục phát huy tinh thân chia sẻ.

                              Comment

                              Về tác giả

                              Collapse

                              vuxuansyhut 3E2K51 - HUT Tìm hiểu thêm về vuxuansyhut

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X