Category Archives: LPC800

Configure PWM using State Configurable Timer (SCT) of LPC 810

Overview

In the course of considering the application of A tiny MML parser, I noticed that LPC 810 was sleeping at hand. A tiny MML parser with 8 pin ARM Cortex – M 0 + is wonderful.

As soon as I looked it up, when considering making it work like Arduino the other day, I found out that it would be better to configure PWM using State Configurable Timer (SCT).

Although it is SCT which is greatly unpopular here and there, I thought that it could actually be used easily.
However, after actually trying, it was a big sinking. Even if you read the register map and function description, you do not understand the meaning at all what way you want it if you set it what you want.

Meanwhile, I found an ex size to let the LED flash on the state machine, so I decided to try it from the head. It can be applied to PWM which only toggle output by applying this.

resource

Exe size resources : http://www.nxp-lpc.com/updated_materials/sct/lpc81x/LPC81x_SCT_code_examples.zip

Exercise presentation : https://onedrive.live.com/view.aspx?resid=7AE40E5A5F1EC907!24470&ithint=file%2cpptx&app=PowerPoint&authkey=!ACDxmgRtdAZZdXE (From slide 30 pages)

Exe size resource

The downloaded exe size resource is the contents at the time of starting work in order to actually finish the project according to the explanation. Set up the project and open the slide 30 page.

 

 

Red State Machine file generator

Red State Machine file generator is a tool to help you configure a state machine and generate source code according to its configuration.
In the Project Explorer, right-click and select “Other …” from “New”.
Select “Red State Machine file generator” from “Red State”.
Enter the file name.

Press the “Choose Target” button to select the target.

The above preparation is completed.
It is the start of exe size.

Step 1

  • Delete U_ALWAYS state
  • Configure the state on the State Table tab
To delete the U_ALWAYS state, right-click U_ALWAYS on the state machine edit screen and select “Delete”.

 

Next, enter the two states on the State Table tab that manages the state.
If you enter a state name or the next state name in this State Table, it will automatically be reflected in the state editing GUI at the center of the screen.

The screen immediately after editing is as follows.

Please drag and move the box showing the state with mouse with a slight arrangement because it is dirty.
Arrows may look bidirectional, but that’s not the case.
Please place it so that it looks like two.

 

Step 2

Next we define the input to the state machine, delay and match 0.

 

Step 3

Add a definition of behavior.

EVENT 0

First, press the plus button at the top right of the Action List tab to add a new action and change the name to EVENT 0.

Define the behavior for EVENT 0.
To do this, move the cursor over the table labeled Operation and right click to do it.

Select “Output pin 0” for the Set operation.

Select “Limit unified counter” for the Call operation.

 

EVENT 1

Define EVENT 1 in the same way.

Change the name to EVENT 1 and add the following actions.
EVENT 1 selects the reverse operation Clear Output pin 0 for EVENT 0.

As with EVENT 0, add Call Limit unified counter as well.

 

Step 4

Once we have defined the behavior, we associate it with the state.
Return to the State Table tab and click the Action column to select the event you defined earlier.

When it is completed it will be as follows.

Just to be sure, let’s check the contents of the Signals tab here.
This value is added automatically when the Signal name is first inserted in the State Table.

Set to treat matches as input.

At this point, the state machine editing screen in the center of the screen is as follows.

Step 5

Open the Outputs for State Machine tab and set the preload value.

Press the Generate Code button to generate the code.

Step 6

Switch workspace and enable SCT initialization code.

Remove the commented out of the commented out place which was implemented beforehand with the exe size code.

Next, open sct_user.h.

The exhaled code implements the definition “#include” board.h “”.
Rewrite it here as “#include” LPC8xx.h “”. There is this definition file in CMSIS enclosed in this exe size.

Why this kind of work is required is that sct_fsm.h is referenced from sct_fsm.c which the tool automatically generated, because the internal implementation of this sct_fsm uses the definition LPC_SCT.

 

The above file name can be preset for Header in sct_user.h of State Machine Settings.

 

Step 7

It is final adjustment.
First, decide the pin to be controlled by the SCT.
Let’s blink the LED of the LPC 800 Mini board this time.
This board has an LED connected to PIO 0 _ 2.

Set the SWM pin assignment register.
Bit 31:24 of the SWM PINASSIGN 6 register is the selection register of CTOUT_ 0.

Select output by adding values ​​in order of 0x00 for PIO0_0 and 0x11 for PIO0_17.
Since it is PIO 0 _ 2 this time, it will be OK to set 0 x 02.

That’s all there is to it.

Other notes

CMSIS Clock Selection

The clock selection of CMSIS is included in the implementation side of system_LPC 8 xx.c.
It must be set according to the board to be operated.

If you make a mistake in this choice, you get confused with “Why does not it work?”

 

Target processor

Correctly select the target processor.
This setting is included in the properties of the project.

This choice changes the linker script given to the tool chain.

Execution result

This time I checked the operation using the LPC 800 mini board. GPO is toggling at 1.6 second cycle, and this operation is performed without CPU intervention. Although it is unknown what is pleasing in this operation cycle, it is a mechanism that PWM operation frequency is changed only by rewriting one register one after another.

Summary

It is considerably difficult to master the new SCT that is installed in the LPC 800 series simply by reading the register map and function explanation. Because it is difficult to read the background of the design and the upper model in the premise from there, and I do not know what value should be set unless you understand what is the register designed on the assumption . In particular, considering transitioning from multiple states according to multiple conditions, it is also necessary to understand the mutual relationship of registers.
I do not know what NXP’s designers thought, but maybe I was surprised that “If you prepare this tool, you will have a microcomputer that you do not have before.” At the time of first spreading in Japan, as a result of a register talk preceding this Red State Machine, it may be that the image “Unknown function” preceded it. (It was definitely meaningless if you read only the register map and function description)
The LPC 800 series SCT may never be an excellent design in the sense that various people are put into various confusions, but I felt the enthusiasm of the designer to try something new. In truth, I do not think that users should feel such enthusiasm, but such trials will lead to the next new thing.
Even though I may be watching Xilinx ‘s Vivado, I may be changing to such a time, leaving the place to leave to the tool, writing by hand with hands.

Learn microcomputers with LPCXpresso and LPC 800 – MAX (Part 9: I2C Switch Control (GPIO))

Probably this time LPCXpresso will be the last, but I will try using I2C. LPC 812 is a small pin so it has few GPIOs, but like Arduino it is extended by connecting the device to the I 2 C bus in order to load GPIO and ADC.

Run the I2C sample program

Let’s start with a sample program. As in the example, select “NXP_LPC 8xx_SampleCodeBundle.zip” from import project (s) and import “I 2 C”. Main is i2ctest.c. However, since this sample code does not work with this LPC 800 – MAX, I made an I 2 C code for GPIO control of LPC 800 – MAX.

Code for “i2c.c”

Delete this code from i2ctest.c and use it. When this code is moved, when the switch of SW 2 is pushed, the red LED glows. It is GPIO control that I gave to the first person, but I2C is used for SW2 switch control.

I 2 C of LPC 800 – MAX

I 2 C device

In the LPC 800 – MAX, two devices are connected to the I 2 C bus

  • PCA9672PW: GPIO expander
  • PCF8591T: ADC / DAC

This time we are using the GPIO expander. Documents of PCA 9672 PW can be found here.

I2C address

I will check the I2C address of the GPIO expander. It is on the circuit diagram.

f:id:tomo_watanabe:20131026223929p:plain

  I2C Addrs = 0b01000 (A1) (A0); Default Addrs = 0b0100011

So it will be 0x23. The I 2 C bus adopts 7 bit address, and it is designed to perform Read / Write control with the lower 1 bit. Therefore, in this case, shift to the left by 1 bit, b01000110 / Write, b01000111 / Read becomes 0x46 / Write, 0x47 / Read respectively. Access to GPIO is read / write with 8 bits (Since it is an AND write, if you want to control only some ports, it is necessary to write after writing OR)

f:id:tomo_watanabe:20131026224646p:plain

Also, looking at the circuit diagram, you can see that P0 to P7 are GPIO and P7 is connected to SW2. IOEXPAN 4, IOEXPAN 5 comes out as Arduino ‘s Digital pin.

f:id:tomo_watanabe:20131026225125p:plain

In addition, although it is “XP_4” and “XP_5” on the board, please be careful because the silk is incorrect.

f:id:tomo_watanabe:20131026225302p:plain

Sample program operation

In the sample program, I2C is initialized and IOEXPAN of the GPIO expander is operated. You can confirm the operation check with a tester etc. After that, the switch of P7 is monitored, and when the switch is pushed, the LED is lit. It is a program called.

I 2 C pin assignment setting

I am doing pin assignment to I2C at the beginning of the code. This neighborhood is the setting of pin march that came out before.

  • SDA: PIO 0 _ 10
  • SLA: PIO 0 _ 11
  / *
    * Initialize I 2 C pin connect
    * /
   / * connect the I2C SCL and SDA sigals to port pins (P0.10 - P0.11) * /
   regVal = LPC_SWM -> PINASSIGN 7 & (0xFFUL << 24);
   LPC_SWM-> PINASSIGN 7 = regVal | (10 << 24); / * P 0. 10 is I 2 C SDA, ASSIGN 0 (31: 24) * /
   regVal = LPC_SWM -> PINASSIGN 8 & (0xFF << 0);
   LPC_SWM-> PINASSIGN 8 = regVal | (11 << 0); / * P 0. 11 is I 2 C SCL. ASSIGN 0 (7: 0) * /
   regVal = LPC_IOCON -> PIO 0 _ 10 & - (0 × 3 << 8);
   LPC_IOCON-> PIO0 - 10 = regVal | (0x2 << 8); / * Enable Fast Mode Plus * /
   regVal = LPC_IOCON -> PIO 0 _ 11 & - (0 × 3 << 8);
   LPC_IOCON-> PIO0_11 = regVal | (0x2 << 8); / * Enable Fast Mode Plus * /

   / * Enable I2C clock * /
   LPC_SYSCON -> SYSAHBCLKCTRL | = (1 << 5);
   / * Toggle peripheral reset control to I2C, a "1" bring it out of reset. * /
   LPC_SYSCON-> PRESETCTRL & = - (0x1 << 6);
   LPC_SYSCON-> PRESETCTRL | = (0x1 << 6);

The latter part is the supply and restart of the clock to the I2C block.

Initialization of I 2 C

  / * For master mode plus, if desired I2C clock is 1 MHz (SCL high time + SCL low time). 
   If CCLK is 36 MHz, MasterSclLow and MasterSclHigh are 0 s, 
   SCL high time = (ClkDiv + 1) * (MstSclHigh + 2)
   SCL low time = (ClkDiv + 1) * (MstSclLow + 2)
   Pre-divider should be 36000000 / (1000000 * 4) -1 = 9-1 = 8. 
   If fast mode, eg communicating with a temp sensor, Max I 2 C clock is set to 400 KHz.
   Pre-divider should be 36000000 / (400000 * 4) -1 = 22.5-1 = 22.
   If standard mode, eg communicating with a temp sensor, Max I 2 C clock is set to 100 KHz.
   Pre-divider should be 36000000 / (100000 * 4) -1 = 90-1 = 89. * /

 I2C_MstInit (LPC_I2C, I2C_FMODE_PRE_DIV, CFG_MSTENA, 0x00);

Since LPC 812 operates as an I2C master this time, it initializes it. There are three types of I2C bus protocol. PIO 0 _ 10 and PIO 0 _ 11 that are assigned this time support all modes. In this setting, Fast-mode operation setting is performed. Also, the master mode is enabled.

  • Standard-mode:
  • Fast-mode:
  • Fast-mode Plus:

After that there are places where I2C is checking whether it is idle, or a buffer is prepared.

Initialization of GPIO (LED initialization)

It is the setting of the GPIO which I did in the early days. Here we are initializing to use the red LED.

  / * GPIO initialization * /
 GPIOInit ();
 GPIOSetDir (0, 7, 1); // RED
 GPIOSetBitValue (0, 7, 1); // RED OFF

Operation of GPIO expander

Write 0 to the GPIO expander once, then write B 0 and confirm it. 0x46 / Write, 0x47 / Read.

  / * Clear GPIO = 0 / GPIO = 0xB0 * /
   uint8_t data;
   I2CMasterTXBuffer [0] = 0x00;
   I2C_MstSend (LPC_I2C, 0x46, (uint8_t *) I2CMasterTXBuffer, 1);
   I2C_MstReceive (LPC_I 2 C, 0 × 47, & data, 1);
   printf ("GPIO:% x \ n", data);
   I2CMasterTXBuffer [0] = 0xB0;
   I2C_MstSend (LPC_I2C, 0x46, (uint8_t *) I2CMasterTXBuffer, 1);
   I2C_MstReceive (LPC_I 2 C, 0 × 47, & data, 1);
   printf ("GPIO:% x \ n", data);

The reason for writing 0xB0 is to set P7 = HIGH, P5 = HIGH, P4 = HIGH at b10110000. This will bring Digital 5, 6 of the Arduino terminal to HIGH. By setting P7 to HIGH, it becomes possible to detect that P7 becomes GND (= 0) by pressing SW2.

Obtaining the switch

Register is being read in the permanent loop. Compared with 0x80, that is, 1 (= HIGH) compared with b1000000, LED is turned off because it is not pushed, and if the 0 (= GND, LOW) switch is pressed, the LED is turned on I will.

  While (1) {
       I2C_MstReceive (LPC_I 2 C, 0 × 47, & data, 1);
       if (data & = 0x80) {
           GPIOSetBitValue (0, 7, 1); // RED OFF
       } else {
           GPIOSetBitValue (0, 7, 0); // RED ON
       }
   }

Summary

For the time being, LPCXpresso built-in microcomputer using LPC 800-MAX is about this. About Arduino or microcontroller

  • GPIO
  • UART
  • I 2 C

If I can pretty much be able to do it, I think that I will manage somehow. It is the price of LPC 812 alone, but you can buy it under @ 200. Since Arduino will do about 3000 in Uno, it will be one digit price different. Of course, it is useless with LPC 812 alone, so that peripheral circuits and debug circuits will be created, so for LPC 812 it will be selected for mass production of 100 or more.

  • Almost verify the operation of peripheral equipment necessary for Arduino . Prototype creation
  • Consider mass production at LPC 812 or MSP 430 (microcomputer of TI).

Will it be like this? If you are looking at mass production to some extent, familiarity with such a microcomputer and sense of cost will become important later.


# I myself is not a circuit shop, so I can not do actual mass production board design, but I can read the circuit diagram so I can pack the hardware requirements for software development with the circuit shop . By being able to read the user’s manual and reading the circuit diagram, the range of software developers will expand. Well I’ll leave it as to whether there is demand (^ _ ^;)

Learn microcomputer with LPCXpresso and LPC 800 – MAX (Part 8: Connect with PC with UART)

Run UART sample program

Let’s start with a sample program. As in the example, select “NXP_LPC 8xx_SampleCodeBundle.zip” from import project (s) and import “UART”. Main is uarttest.c. This sample program is a program that connects to PC terminal software etc. with UART and returns echo by looping back input from PC. For that purpose, we need to connect PC and LPC 800 – MAX, so connection diagram is shown.

f:id:tomo_watanabe:20131016131300p:plain

Connect 0 pin of LPC 800 – MAX to TX of serial adapter, 1 pin RX, GND. As a caution, LPC 800 – MAX is 3.3 V drive, so when using USB serial adapter, use 3.3 v compatible. For the PC terminal software, set the baud rate to 9600. The rest is decided, data bit 8,, stop bit 1, no parity, no flow control. In this state I will try to run it in the debug build (unless you change it to redlib (semihost), it will result in an error)

f:id:tomo_watanabe:20131016124601j:plain

The green LED will light (this is described as a bonus). On the other hand, ” Hello World !” Is displayed on the PC terminal. When you enter a character in the terminal, it is echoed back and the characters are displayed.

f:id:tomo_watanabe:20131016132644p:plain

Watch the operation of UART

Setting of UART pin assignment

The code is #if with some blocks, but this is a story of RX and TX UART block and pin assignment, so I will see #if 1 only.

  / * connect the UART0 TXD abd RXD sigals to port pins (P0.4 - P0.0) * /
 regVal = LPC_SWM -> PINASSIGN 0 & (0xFF << 0);
 LPC_SWM-> PINASSIGN 0 = regVal | (4 << 0); / * P 0. 4 is UART 0 TXD, ASSIGN 0 (7: 0) * /
 regVal = LPC_SWM -> PINASSIGN 0 & (0xFF << 8);
 LPC_SWM -> PINASSIGN 0 = regVal | (0 << 8); / * P 0. 0 is UART 0 RXD. ASSIGN 0 (15: 8) * /
    
 regVal = LPC_SWM -> PINASSIGN 0 & (0xFF << 16);
 LPC_SWM -> PINASSIGN 0 = regVal | (12 << 16); / * P 0. 12 is UART 0 RTS, ASSIGN 0 (23:16) * /
 regVal = LPC_SWM -> PINASSIGN 0 & (0xFFUL << 24);
 LPC_SWM-> PINASSIGN 0 = regVal | (13 << 24); / * P 0. 13 is UART 0 CTS. ASSIGN 0 (31: 24) * /

This part has pin assignment of UART RX, TX, RTS , CTS .

  • TXD: PIO 0 _ 4
  • RXD: PIO 0 _ 0
  • RTS : PIO 0 _ 12
  • CTS : PIO 0 _ 13

In the circuit diagram of LPC 800 – MAX, TX and RX are assigned to 1 pin and 0 pin as Digital pins, respectively. Just this pin arrangement is arranged in the same way as Arduino (though it is natural)

f:id:tomo_watanabe:20131016133814p:plain

In this example, we set the so-called pin-mini setting to allocate the UART terminal to PIO. In the LPC 800 series, since the number of pins is small in proportion to the function, it is set to GPIO in the default state, but by using this internal pin-march function, you can assign pins of function block you want to use to GPIO I will. Normally pin marching has many restrictions, but in the LPC 800 series it is quite freely assignable and is called Switch Matrix function. Detailed information is written in Cortex-M 0 + with LPC 800 series – small pin package, switch matrix . I will look at the setting. There is register setting of Switch Matrix in user’s manual p122 – p124

f:id:tomo_watanabe:20131016143504p:plain

Looking at Pin assigne register 0, it seems that it is assigned by writing the PIO number in the corresponding bit range (word setting). To assign TXD to PIO 0 _ 4, write 4 with [7: 0]. Other pin assignments are done in the same way.

f:id:tomo_watanabe:20131016143837p:plain

Initialization of UART communication

Since UART pin assignment was done at initialization, initialize UART.

  UARTInit (LPC_USART 0, 9600);

This is the UARTInit function. Since UART code is also provided by ARM, details are omitted. Well, it seems to be okay to keep it as it is for normal use. (Although there are severe settings such as strictly selecting the generation clock of the baud rate, etc.) Set the baud rate and the channel of UART to use with the function provided in lpc8xx_uart.c. For USART (Asynchronous and synchronous can be used), two channels or three channels are prepared for LPC 812 (Package is different) Which? If you think that there is no setting like flow control or parity

  (lpc 8 x x _ uart.c)

 void UARTInit (LPC_USART_TypeDef * UARTx, uint32_t baudrate)
 {
     uint32_t UARTSysClk;
        
   UARTTxEmpty = 1;
    
     UARTClock_Init (UARTx);
    
     UARTSysClk = SystemCoreClock / LPC_SYSCON -> UARTCLKDIV;
    
   UARTx-> CFG = DATA_LENG_8 | PARITY_NONE | STOP_BIT_ 1; / * 8 bits, no Parity, 1 Stop bit * /
 / * UARTx-> CFG = DATA_LENG_7 | PARITY_NONE | STOP_BIT_ 1; / * 7 bits, no Parity, 1 Stop bit * /
 // UARTx-> CFG = DATA_LENG_8 | PARITY_NONE | STOP_BIT_ 2; / * 8 bits, no Parity, 2 Stop bit * /
 // UARTx-> CFG = DATA_LENG_8 | PARITY_EVEN | STOP_BIT_ 1; / * 8 bits, even Parity, 1 Stop bit * /
 // UARTx-> CFG = DATA_LENG_8 | PARITY_ODD | STOP_BIT_ 1; / * 8 bits, odd Parity, 1 Stop bit * /

Commented out … … orz UART also needs to rewrite this driver if you want to set the details yourself … (; ‘Д `)

Reception / transmission processing

The actual reception / transmission processing is the following part. We send ” Hello World !” By UART with UARTSend function and are waiting to receive with permanent loop. Transmission is UART channel, transmission data, size.

  UARTSend (LPC_USART 0, (uint 8 _ t *) "Hello World! \ R \ n", 14);
   for (i = 0; i <0 × 10000; i ++);

   while (1)
   {
       if (UARTRxCount &&! RxErrorCount)
       {
           LPC_USART 0 -> INTENCLR = RXRDY; / * Disable RXRDY * /
           UARTSend (LPC_USART 0, (uint 8 _ t *) UARTRxBuffer, UARTRxCount);
           UARTRxCount = 0;
           LPC_USART 0 -> INTENSET = RXRDY; / * Re - enable RXRDY * /
       }
   }
 }

Although it is reception, this also feels subtle to the implementation (゜. ゜) … UARTRxCount is the number of data received, so if there is incoming data and the error bit is not set up.

  1. Receive interrupt clear
  2. Send the contents of the receive buffer as it is
  3. Clear received data size
  4. Receive interrupt enabled

It has become the trend. With this, data received (input from PC) is echoed back . However, this implementation is not very good at handling the variables used by the driver here … (; ‘Д `) Something like the sample code is something like this, is not it?


bonus. Why does the LED light up?

Well, I think I understood the operation of UART. One? There was a part I thought so I supplement it. When you run this sample program on LPC 800 – MAX, the LED will light green. I do not remember what GPIO set up … so I will investigate there. Actually I used it for debugging this first time since Blinky. The answer was the answer.

  / * Config CLKOUT, mostly used for debugging. * /
 regVal = LPC_SWM -> PINASSIGN 8;
 regVal & = ~ (0xFF << 16);
 regVal | = (17 << 16);
 LPC_SWM -> PINASSIGN 8 = regVal; / * P 0. 17 is CLKOUT, ASSIGN (23: 16). * /
 CLKOUT_Setup (CLKOUTCLK_SRC_MAIN_CLK);

When I looked at what I was doing, I output CLCKOUT to a specific pin externally. For this program, CLCKOUT, possibly 12 MHz, is output to PIO 0 _ 17. I did it with LPCXpresso and LPC 800 – MAX with a microcomputer (Part 3: Check LED operation (GPIO)) , but the LPC 800 – MAX board was connected to the green LED on PIO 0 _ 17. Since CLCKOUT is output here, it functions as PWM, so it lights up in green. What I am doing specifically is

  • Set CLCKOUT pin to PIO 0 _ 17 with Switch Matrix register
  • Set CLCKOUT to 12 MHz of main clock

f:id:tomo_watanabe:20131012211624p:plain

CLKOUT is in the middle right. The CLKOUT_Setup function sets the CLKOUT source clock. In the function, the source clock is selected and divided by CLKOUTDIV for CLKOUT. However, it is somewhat strange that the LED is lit even though CLKOUTDIV should be disable because its initial setting is 0. Hate

f:id:tomo_watanabe:20131016161116p:plain

After that, by writing CLKOUTDIV = 1, 12 MHz should be outputted, but if you have an oscilloscope you should be able to ascertain this side but I do not have it … orz

Learn microcomputer with LPCXpresso and LPC 800-MAX (Part 7: Use Systick timer)

We used MRT (Multi-rate Timer) the last time, but this time we will try to move Systick timer sample as an example. The Systick timer is a timer in Cortex – M 0 +, with only 1 channel. There was a description somewhere that this timer is usually used as an OS timer.

Systick sample program

Just like importing Blinky’s samples, I will import the Systick sample this time. The main program is systicktest.c. First of all, when this is operated, the red LED will move so that it flashes. Let’s see the whole quickly.

As far as you saw the source, you can imagine roughly. In the flashing part of the LED, GPIO initialization is performed with GPIOInit function, 7 pin is switched to output, and the output is turned ON / OFF in the while loop. For Systick, we initialize with Systick_Config function and use Systick timer with delaySysTick function.

  (systicktest.c)

 #define SYSTICK_DELAY (SystemCoreClock / 100)

 :

 int main (void) 
 {
   SystemCoreClockUpdate ();

   / * Called for system library in core_cmx.h (x = 0 or 3). * /
   SysTick_Config (SYSTICK_DELAY);
  
   GPIOInit ();
  
   / * Set port 0_7 to output * /
   GPIOSetDir (0, 7, 1);

   while (1) / * Loop forever * /
   {
     delaySysTick (10);
     GPIOSetBitValue (0, 7, 0);
     delaySysTick (10);
     GPIOSetBitValue (0, 7, 1);
   }
 }

Systick timer

Initialization of Systick timer

Initialization of Systick timer is done by Systick_Config function. As argument is SYSTICK_DELAY = SystemCoreClock / 100, it seems to have created a 10ms timer (as it seems), look at the function of Systick_Config.

  (core_cm 0 plus.h)

 __STATIC_INLINE uint32_t SysTick_Config (uint32_ t ticks)
 {
   if ((ticks - 1)> SysTick_LOAD_RELOAD_Msk) return (1); / * Reload value impossible * /

   SysTick-> LOAD = ticks - 1; / * set reload register * /
   NVIC_SetPriority (SysTick_IRQn, (1 << __ NVIC_PRIO_BITS) - 1); / * set Priority for Systick Interrupt * /
   SysTick-> VAL = 0; / * Load the SysTick Counter Value * /
   SysTick-> CTRL = SysTick_CTRL_CLKSOURCE_Msk |
                    SysTick_CTRL_TICKINT_Msk |
                    SysTick_CTRL_ENABLE_Msk; / * Enable SysTick IRQ and SysTick Timer * /
   return (0); / * Function successful * /
 }

Skip the first mask and see the assignment to the register . The name is slightly different but the correspondence that comes out here is below. User’s Manual p.180

  • Systick-> LOAD: SYST_RVR
  • Systick-> VAL: SYST_CVR
  • Systick-> CTRL: SYST_ CSR

f:id:tomo_watanabe:20131014234129p:plain

Set the timer setting value in the SYST_RVR register (why is it doing -1?) Writing the value in the SYST_CVR register clears the Systick timer.

f:id:tomo_watanabe:20131014235116p:plain

By writing 1 to CLKSOURCE, TICKINT, ENABLE in SYST_CSR, the clock source is set to the system clock, the interrupt is enabled, and the timer is enabled.

f:id:tomo_watanabe:20131014235452p:plain

It seems that NVIC_SetPriority function sets the interrupt priority of this Systick, but if you deeply deep here, you will keep track of the contents of Cortex – M 0 +. Since the code of this part is provided by ARM, it seems that there is normally no necessity to tweak (it may be necessary if you want to crispy course, of course)

Interrupt handler

For GPIOInit function and GPIO operation, I think that I understand mostly what you are doing, so I will omit it. Since Systick’s initial setting was made, when looking at timer interrupt processing this time, it was only incrementing TimeTick. This is the same as MRT. The difference is that it does not manipulate the interrupt judgment register (there is only 1 channel, so it is not necessary). Now, when the Systick timer is this sample, we noticed that the interrupt was entered at 10 ms and TimeTick counted up.

  / * SysTick interrupt happens every 10 ms * /
 void SysTick_Handler (void)
 {
   TimeTick ++;
 }

Weight function

The remaining function is the delaySysTick function. It is literally a function that performs delay (weight). Before and after processing, Systick’s timer is enabled and disabled.

  void delaySysTick (uint32_t tick)
 {
   uint32_t timetick;

   / * Clear SysTick Counter * /
   SysTick -> VAL = 0;
   / * Enable the SysTick Counter * /
   SysTick-> CTRL | = (0x1 << 0);

   timetick = TimeTick;
   while ((TimeTick - timetick) <tick);
  
   / * Disable SysTick Counter * /
   SysTick-> CTRL & = - (0x1 << 0);
   / * Clear SysTick Counter * /
   SysTick -> VAL = 0;
   return;
 }

In the weight part, we are only turning the difference between timetick and TimeTick. Since TimeTick is counted up in units of 10 ms, it is a process to exit at the set time (· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · )

weak symbol

I understand the action of the unit by this. If we do not know the concept of another weak symbol, we can not properly design the handler. Weak symbols are described with weak symbols . A function close to overloading in C ++ , a function declared as weak can describe the default behavior, and if there is a function with the same name, it seems that it is linked with priority. In this example, “void SysTick_Handler (void)” is equivalent. Where is the default?

  (cr_startup_lpc 8 xx.c)

 #define WEAK __attribute__ ((weak))
 :
 WEAK void SysTick_Handler (void);
 :
 __attribute__ ((section (". after _vectors"))))
 void SysTick_Handler (void)
 {
     while (1)
     {
     }
 }

It is declared like this, and by default it comes into an endless loop. Please try out and comment out the Systick_Handler function of the sample and build it. The build goes through (it moves into an endless loop and deadlocks )

This time it is over, next I will do UART. Finally it has become a practical feeling. However, every sample is a subtle implementation … (; ‘Д `)

Learn microcomputer with LPCXpresso and LPC 800-MAX (Extra edition: about provided code)

I touched LPCXpresso and I have something to worry about, so write it down. LPC 812 is a microcomputer combining ARM’s Cortex – M 0 + core and NXP peripheral modules. The block diagram can be found in user’s manual p7.

f:id:tomo_watanabe:20131013235759p:plain

When I looked at the sample program I thought that it was “Paradox” that “I guess this is not quality at all”? For example, in MRT of the previous entry, there is only 0 channel implementation and you only need to increase the channel number in the argument, why? Trying to look at it, found the following description at the top of the MRT code!

  / ************************************************* ***************************
  * $ Id :: lpc8xx_mrt.c 5543 2012-10-31 02: 19: 19Z usb00423 $
  * Project: NXP LPC 8xx multi-rate timer (MRT) example
  *
  * Description:
  * This file contains MRT timer code example which include timer 
  * initialization, timer interrupt handler, and related APIs for 
  * timer setup.
  *
  ************************************************** **************************

“exmaple” · · · What! What? Even if it is officially a project file called “lpc_driver_lib”? A little Mate, other code too? I thought and tried it. The drivers with the description “example” are as follows (although it is exmaple, there may be some good quality so far, I have not looked it up)

  • MRT (lpc8xx_mrt.c)
  • Clock Configuration (lpc8xx_clkconfig.c)
  • CMP (lpc8xx_comp.c)
  • CRC (lpc 8 x x _ crc)
  • GPIO (lpc8xx_gpio.c)
  • NMI (lpc 8 x x _ nmi.c)
  • PMU (lpc 8 x x _ pm.c)
  • WDT (lpc8xx_wdt.c)
  • WKT (lpc 8 x x _ wkt.c)

The officially supported code is

  • I 2 C (lpc 8 x x _ i 2 c)
  • UART (lpc 8 x x _ uart.c)
  • SPI (lpc 8 x x _ spi.c)

The code of Cortex – M 0 + side of the ARM core seems to be officially supported. That’s why most of the code on the LPC side is a sample driver. Well surely the driver is a part that needs to be made according to each circumstance, but I feel like I want to keep trying a bit more … (; ‘Д `) Well it might be just a register macro …

This may not be prevalent unless someone creates a library and publishes … Even so, embedded engineers do not go out and can not share know-how (‘ ε `;;) Woo …

Learn microcomputer with LPCXpresso and LPC 800-MAX (part 6: use timer)

This time I will return to Blinky’s sample and want to check the operation of the remaining timer.

LPC 800 series timer

The LPC 800 series has two kinds of timers.

  • Systick timer in Cortex- M0 +, 24bit 1 channel
  • MRT (Multi-rate Timer) as LPC series, 31 bit 4 channel

Blinky uses the MRT to blink the LEDs. There are some places as “?” As to how to write samples, but for the time being we will look.

Overall behavior

The part which is blinking LED is the following part.

  extern uint32_t mrt_counter;

 :

   init_mrt (0x8000);

   while (1) / * Loop forever * /
   {
     / * I / O configuration and LED setting pending. * /
     if ((mrt_counter> 0) && (mrt_counter <= 200))
     {
         GPIOSetBitValue (0, 7, 0);
     }
     if ((mrt_counter> 200) && (mrt_counter <= 400))
     {
         GPIOSetBitValue (0, 7, 1);
     }
     if ((mrt_counter> 400) && (mrt_counter <= 600))
     {
         GPIOSetBitValue (0, 16, 0);
     }
     if ((mrt_counter> 600) && (mrt_counter <= 800))
     {
         GPIOSetBitValue (0, 16, 1);
     }
     if ((mrt_counter> 800) && (mrt_counter <= 1000))
     {
         GPIOSetBitValue (0, 17, 0);
     }
     if ((mrt_counter> 1000) && (mrt_counter <= 1200))
     {
         GPIOSetBitValue (0, 17, 1);
     }
     else if (mrt_counter> 1200)
     {
         mrt_counter = 0;
     }
   }

Initializing MRT with the init_mrt function and checking the value of mrt_counter makes it possible to adjust the blinking interval. How about extern variables like mrt_counter normally at this point? I will feel it but I will not mind (^ ^;

Initialization of MRT (Multi-rate Timer)

Let’s look at the init_mrt function.

  (lpc8xx_mrt.c)

 void init_mrt (uint32_t TimerInterval) 
 {
   / * Enable clock to MRT and reset the MRT peripheral * /
   LPC_SYSCON -> SYSAHBCLKCTRL | = (0x1 << 10);
   LPC_SYSCON -> PRESETCTRL & = - (0x1 << 7);
   LPC_SYSCON-> PRESETCTRL | = (0x1 << 7);

   mrt_counter = 0;
   LPC_MRT-> Channel [0]. INTVAL = TimerInterval;
   LPC_MRT-> Channel [0]. INTVAL | = 0x 1 UL << 31;
    
   LPC_MRT-> Channel [0] .CTRL = MRT_REPEATED_MODE | MRT_INT_ENA;
    
   / * Enable the MRT Interrupt * /
   NVIC_EnableIRQ (MRT_IRQn);

   return;
 }

First, 1 is written to the 10th bit of the SYSAHBCLKCTRL register , and the clock is supplied to the MRT block.

  LPC_SYSCON -> SYSAHBCLKCTRL | = (0x1 << 10);

The MRT block is reset by the Peripheral reset control register on the next two lines. It is in user ‘s manual p. 28.

f:id:tomo_watanabe:20131013223521p:plain

f:id:tomo_watanabe:20131013223530p:plain

After writing 0, I write 1 and reset the block.

  LPC_SYSCON -> PRESETCTRL & = - (0x1 << 7);
   LPC_SYSCON-> PRESETCTRL | = (0x1 << 7);

We initialize the global variable mrt_counter and set the timer value. Here, MRT should have 4 channels, but for some reason 0 channel is fixed. MRT from user’s manual p 162

f:id:tomo_watanabe:20131013224135p:plain

The manual has a description for 4 channels properly. The LOAD bit is written so that the timer setting value is written to the Time interval register and the timer is started immediately at the 31st bit. User’s manual p163

f:id:tomo_watanabe:20131013224423p:plain

  mrt_counter = 0;
   LPC_MRT-> Channel [0]. INTVAL = TimerInterval;
   LPC_MRT-> Channel [0]. INTVAL | = 0x 1 UL << 31;

Next, we set the control register to repeat mode and enable the interrupt.

f:id:tomo_watanabe:20131013224718p:plain

  LPC_MRT-> Channel [0] .CTRL = MRT_REPEATED_MODE | MRT_INT_ENA;

Finally, MRT interrupt is enabled so that a timer interrupt is made to enter.

  / * Enable the MRT Interrupt * /
   NVIC_EnableIRQ (MRT_IRQn);

What is this NVIC_EnableIRQ function doing? Looking at IRT_IRQn

  typedef enum IRQn
 {
 / ****** Cortex-M 0 Processor Exceptions Numbers ************************************* ************** /
   Reset_IRQn = -15, / *! <1 Reset Vector, invoked on Power up and warm reset * /  
   NonMaskableInt_IRQn = -14, / *! <2 Non Maskable Interrupt * /
   HardFault_IRQn = -13, / *! ❤ Cortex-M 0 Hard Fault Interrupt * /
   SVCall_IRQn = -5, / *! <11 Cortex-M 0 SV Call Interrupt * /
   PendSV_IRQn = -2, / *! <14 Cortex-M 0 Pend SV Interrupt * /
   SysTick_IRQn = -1, / *! <15 Cortex-M 0 System Tick Interrupt * /

 / ****** LPC 8 xx Specific Interrupt Numbers *************************************** ***************** /
   SPI 0 _IRQn = 0, / *! <SPI 0 * /
   SPI1_IRQn = 1, / *! <SPI1 * /
   Reserved 0 _ IRQn = 2, / *! <Reserved Interrupt * / 
   UART 0 _ IRQn = 3, / *! <USART 0 * /
   UART1_IRQn = 4, / *! <USART1 * /
   UART 2 _IRQn = 5, / *! <USART 2 * /
   Reserved 1 _IRQn = 6, / *! <Reserved Interrupt * /    
   Reserved 2 _IRQn = 7, / *! <Reserved Interrupt * /
   I2C_IRQn = 8, / *! <I2C * /
   SCT_IRQn = 9, / *! <SCT * /
   MRT_IRQn = 10, / *! <MRT * /

As an interrupt number, you can see that MRT is assigned to number 10. Now in NVIC_EnableIRQ,

  __STATIC_INLINE void NVIC_EnableIRQ (IRQn_Type IRQn)
 {
   NVIC -> ISER [0] = (1 << ((uint32 - t) (IRQn) & 0 x 1 F));
 }

The interrupt number is set as ISER [0] of NVIC as an argument. The NVIC register is located in user’s manual p14 and ISER is on page 15.

f:id:tomo_watanabe:20131013225648p:plain

f:id:tomo_watanabe:20131013225821p:plain

That is, MRT interrupts are enabled in the Interrupt Set Enable register of the NVIC. NVIC is the “Nested Vector Interrupt Controller” and the essential is “interrupt controller”. More than that is good here.

Now, when the timer is set and the timer value counts down and becomes 0, the MRT interrupt will operate.

Interrupt handler

Next, check the operation when an interrupt occurs. Interrupt handler implementation

  (lpc8xx_mrt.c)

 void MRT_IRQHandler (void)
 {  
   if (LPC_MRT-> Channel [0] .STAT & MRT_STAT_IRQ_FLAG)
   {
     LPC_MRT-> Channel [0] .STAT = MRT_STAT_IRQ_FLAG; / * clear interrupt flag * /
     mrt_counter ++;
   }
   return;
 }

When the timer value counts down and becomes 0, this interrupt handler is called. As a whole we just increment the global variable mrt_counter. Well let’s look in detail.

First, it checks whether the interrupt flag is set in the Status register of the 0 channel of the MRT.

f:id:tomo_watanabe:20131013231858p:plain

  if (LPC_MRT-> Channel [0] .STAT & MRT_STAT_IRQ_FLAG)

If the interrupt flag is set, the interrupt flag is cleared. Writing 1 to INTFLAG clears it. After clearing, the counter is incremented by 1 and it is over.

  LPC_MRT-> Channel [0] .STAT = MRT_STAT_IRQ_FLAG; / * clear interrupt flag * /
 mrt_counter ++;

Blinking behavior of LED

I understood the operation of MRT. The value set by the init_mrt function acts as a counter, counts down, and when it becomes 0, mrt_counter is +1. Therefore, the operation of the sample program flashes at the timing of 0x8000 (32768) x 200. When the mrt_counter exceeds 1200, it is reset to 0 and it will repeat.

Note: Although mrt_counter is globally initialized in init_mrt, it clears to 0 in the main program, or it is a bad sample. Let’s not write such a program (^ ^;

Try changing the timing

Let’s change the timing of the timer. It is like this.

  // init_mrt (0x8000);
   init_mrt (SystemCoreClock / 100);

Since mrt_counter flashes at 200, this means that it flashes every 2 seconds. What? What? I do not quite understand. I will explain it. The timer eventually moves in synchronization with the clock frequency. Well SystemCoreClock = 12 MHz. This is the frequency of 1 second. In other words, setting it to 120000 will result in a 1 second timer. Since it is dividing by 100, it means that 10 ms timer is set. Since the flashing count is 200, it means 10 ms × 200 = 2 s. Actual timers are created in units of 10 ms or 1 ms like this, so it will be like this setting.

Next time I will try supplementing timers using Systick instead of MRT and handlers I could not explain this time.

Learn microcomputer with LPCXpresso and LPC 800 – MAX (part 5: clock up using PLL!)

Since the maximum operation clock of LPC 812 is 30 MHz, this time we will change the setting to operate the default 12 MHz at 30 MHz.

How to change the operation clock

Consider referring to the clock generator of the previous entry .

f:id:tomo_watanabe:20131012211624p:plain

The goal is to make “system clock” 30 MHz. Well, although it is the type of input clock,

  • IRC oscillator
  • XTALIN, XTALOUT
  • CLKIN
  • watchdog oscillator

Although it seems possible to select, the clock generator has restrictions.

f:id:tomo_watanabe:20131012230344p:plain

The input frequency of the watchdog oscillator is too low to be usable. CLKIN is not connected to the clock in the first place on the circuit diagram. XTALIN, XTALOUT but in the circuit diagram …

f:id:tomo_watanabe:20131012230654p:plain

Implementation is done, but it is not actually connected with a jumper. Therefore, only IRC oscilator (internal oscillator) can be used. Now how can I make 30 MHz with 12 MHz internal oscillator? The answer can be made by multiplying / dividing with the PLL circuit. There is a description in this user manual p50.

f:id:tomo_watanabe:20131012231528p:plain

Since we want to make System clock = 30 MHz using PLL this time, we can make Main clock = 60 MHz. In that case

  • M divider value: 5
  • P divider value: 2

There is something called. This is the setting value of the PLL circuit. There are various descriptions slightly above this table, and the constraints of the PLL circuit are written.

f:id:tomo_watanabe:20131012234850p:plain

Organizing it will be like this.

f:id:tomo_watanabe:20131012234428p:plain

Now, since PLL input = 12 MHz, Main clock = 60 MHz, System clock = 30 MHz, SYSAHBCLKDIV = 2. For M and P

f:id:tomo_watanabe:20131013004323p:plain

From this equation,

  • M = 60 MHz / 12 MHz = 5
  • Since FCCO = 2 × P × 60 MHz (156 MHz <FCCO <320 MHz), P = 2

I will set it concretely

Let’s set up the above setting concretely. Change the setting value of system_LPC8xx.c. The register to be changed is

  • SYSPLLCTRL: Set M and P of PLL
  • MAINCLKSEL: Set main clock selection to PLL out
  • SYSAHBCLKDIV: Generate the system clock 1/2 from the main clock
  #define CLOCK_SETUP 1
 #define SYSOSCCTRL_Val 0x00000000 // Reset: 0x000
 #define WDTOSCCTRL_Val 0x00000000 // Reset: 0x000
 // # define SYSPLLCTRL_Val 0x00000041 // Reset: 0x000
 #define SYSPLLCTRL_Val 0x00000024 // Reset: 0x000 M = 5, P = 2
 #define SYSPLLCLKSEL_Val 0x00000000 // Reset: 0x000
 // # define MAINCLKSEL_Val 0x00000000 // Reset: 0x000
 #define MAINCLKSEL_Val 0x00000003 // Reset: 0x000 PLL select
 // # define SYSAHBCLKDIV_Val 0x00000001 // Reset: 0x001
 #define SYSAHBCLKDIV_Val 0x00000002 // Reset: 0x001 1/2

However, there is attention. As the default is SYSAHBCLKDIV = 1, if you start clock generation from the previous stage, the moment the main clock 60 MHz is output, the system clock will also be 60 MHz. Therefore, it is safer to first set SYSAHBCLKDIV = 2, and set the system clock to 1/2 of the main clock beforehand. Modify the code as follows.

  LPC_SYSCON-> SYSAHBCLKDIV = SYSAHBCLKDIV_Val; <- For safety reasons LPC_SYSCON-> SYSPLLCLKSEL = SYSPLLCLKSEL_Val; / * Select PLL Input * /
   LPC_SYSCON-> SYSPLLCLKUEN = 0x01; / * Update Clock Source * /
   while (! (LPC_SYSCON-> SYSPLLCLKUEN & 0x01)); / * Wait Until Updated * /
 #if ((MAINCLKSEL_Val & 0x03) == 3) / * Main Clock is PLL Out * /
   LPC_SYSCON-> SYSPLLCTRL = SYSPLLCTRL_Val;
   LPC_SYSCON-> PDRUNCFG & = - (0x1 << 7); / * Power-up SYSPLL * /
   while (! (LPC_SYSCON-> SYSPLLSTAT & 0x01)); / * Wait Until PLL Locked * /
 # endif

 #if (((MAINCLKSEL_Val & 0x03) == 2))
   LPC_SYSCON-> WDTOSCCTRL = WDTOSCCTRL_Val;
   LPC_SYSCON-> PDRUNCFG & = ~ (0x1 << 6); / * Power-up WDT Clock * /
   for (i = 0; i <200; i ++) __NOP ();
 # endif

   LPC_SYSCON-> MAINCLKSEL = MAINCLKSEL_Val; / * Select PLL Clock Output * /
   LPC_SYSCON-> MAINCLKUEN = 0x01; / * Update MCLK Clock Source * /
   while (! (LPC_SYSCON-> MAINCLKUEN & 0x01)); / * Wait Until Updated * /

 // LPC_SYSCON-> SYSAHBCLKDIV = SYSAHBCLKDIV_Val; <--- comment out

I will check the operation

I will display SystemCoreClock using printf for operation confirmation.

f:id:tomo_watanabe:20131013012106p:plain

It was confirmed that it was 30 MHz as set up. Here is a method to check the register on the IDE. With break, select the “Peripherals +” tab from the project window on the left and check “SYSCON” for Peripheral now. In this state, when you select the “Memory” tab in the lower right console window, the current value of each register is displayed.

f:id:tomo_watanabe:20131013012814p:plain

It can be confirmed that each register is set as specified. Checking of this register can be used for GPIO and others, and it can also be used for debugging as it can change the value of “Value” on the spot.


Last time and this time I checked the startup routine and operation clock setting. In a PIC microcomputer like Arduino usually you do not have to worry about such things. However, if you do not do more than prototype or choose the microcomputer to incorporate into the product considering the cost etc., you will need to use the embedded microcomputer. The method and the basic way of thinking here are almost the same for any microcomputer, so if you keep even basic, it will be possible to apply it.

Learn microcomputer with LPCXpresso and LPC 800 – MAX (part 4: startup routine)

Take a look at the startup routine

The sample application of Blinky started from the main function of mai.c, but here I will look at the startup routine at startup up to this point. In the startup routine, important initialization and default settings at startup are done

Where is the main function called?

If you examine where the main function of main.c is called, you can see that it is called from cr_startup_lpc8xx.c. To be exact, “_ REDLIB_ ” is valid, main is called after __main in Redlib. Also, you can run the main function, and if it should come out, you can see that it will be in a permanent loop of while.

  (cr_startup_lpc 8 xx.c)

 #if defined (__REDLIB__)
     // Call the Redlib library, which in turn calls main ()
     __main ();
 # else
     main ();
 # endif

     //
     // main () should not return, but if it does, we'll just enter an infinite loop
     //
     While (1) {
         ;
     }
 }

The function calling this main function is a function called ResetISR. This is a reset handler and will jump to here when reset. In other words, this RestISR will start the program.

SystemInit function

In ResetISR, the SystemInit function is called to initialize the system, and then the main function is executed. At the beginning of ResetISR, I move the vector table from Flash to SRAM (function of Cortex – M 0 +), initialize the data area, etc.

Let’s look inside SystemInit. Removing the invalid part in ifdef will result in the following.

  (system_LPC 8 xx.c)

 void SystemInit (void) {
   volatile uint32_t i;

   / * System clock to the IOCON & the SWM need to be enabled or
   Most of the I / O related peripherals will not work. * /
   LPC_SYSCON-> SYSAHBCLKCTRL | = ((0x1 << 7) | (0x1 << 18));

   LPC_SYSCON-> SYSPLLCLKSEL = SYSPLLCLKSEL_Val; / * Select PLL Input * /
   LPC_SYSCON-> SYSPLLCLKUEN = 0x01; / * Update Clock Source * /
   while (! (LPC_SYSCON-> SYSPLLCLKUEN & 0x01)); / * Wait Until Updated * /

   LPC_SYSCON-> MAINCLKSEL = MAINCLKSEL_Val; / * Select PLL Clock Output * /
   LPC_SYSCON-> MAINCLKUEN = 0x01; / * Update MCLK Clock Source * /
   while (! (LPC_SYSCON-> MAINCLKUEN & 0x01)); / * Wait Until Updated * /

   LPC_SYSCON-> SYSAHBCLKDIV = SYSAHBCLKDIV_Val;
 }

I will explain each line. This can be checked against the user’s manual.

  Supplies clocks to blocks of SWM (Switch Matrix) and IOCON (I / O configuration) for validity.
 LPC_SYSCON-> SYSAHBCLKCTRL | = ((0x1 << 7) | (0x1 << 18));

 #define SYSPLLCLKSEL_Val 0x00000000 // Reset: 0x000
 :
 System PLL clock source selection.  Select IRC from the above values ​​LPC_SYSCON-> SYSPLLCLKSEL = SYSPLLCLKSEL_Val; <----- 1
 System PLL update LPC_SYSCON-> SYSPLLCLKUEN = 0x01;
 while (! (LPC_SYSCON-> SYSPLLCLKUEN & 0x01)); 

 #define SYSPLLCLKSEL_Val 0x00000000 // Reset: 0x000
 :
 Main clock source selection.  Based on the above values ​​IRC Oscillator (using internal oscillator)
 LPC_SYSCON-> MAINCLKSEL = MAINCLKSEL_Val; <----- 2
 Main clock update LPC_SYSCON-> MAINCLKUEN = 0x01;
 while (! (LPC_SYSCON -> MAINCLKUEN & 0x01));

 #define SYSAHBCLKDIV_Val 0x00000001 // Reset: 0x001
 :
 Setting of the division ratio of the system clock.  From the above values ​​1
 LPC_SYSCON-> SYSAHBCLKDIV = SYSAHBCLKDIV_Val; <----- 3

Operation clock setting

Well what do you guys do? I understand that some initial setting is done around the clock. The above settings are set in the following figure. The following is a block diagram of the clock generator, but the above 1 to 3 set ① to ③.

f:id:tomo_watanabe:20131012211624p:plain

For the correspondence with this figure, select IRC oscillator in SYPLLCLKSEL, select IRC oscillator instead of preceding PLL output in MAINCLKSEL in the next stage, divide it by SYSAHBCLKDIV to make it the system clock. In other words,

  • main clock: IRC oscillator
  • system clock: main clock / 1

. System clock = main clock = clock number of the internal oscillator. How many clocks do the internal oscillator have? It is written in user’s manual p5.

f:id:tomo_watanabe:20131012212651p:plain

Therefore, the system clock will operate at 12 MHz. The LPC 812 can operate at 30 MHz, but the initial value is suppressed. Let’s check that it actually operates at 12 MHz. You can check it with the first SystemCoreClockUpdate function of the main function. Since there is an assignment to SystemCoreClock at the end of the SystemCoreClockUpdate function, check at the break point after setting a break point thereafter. * Please note that the screenshot below is before the assignment because of the screenshot creation convenience. It is the return exit place to actually check

f:id:tomo_watanabe:20131012213916p:plain

Sure it has become 12 MHz. Where the setting on the actual code is done is described below in the SystemCoreClockUpdate function.

  switch (LPC_SYSCON-> MAINCLKSEL & 0x03) {
     case 0: / * Internal RC oscillator * /
       SystemCoreClock = __IRC_OSC_CLK; <-------- break once determined here;
     case 1: / * Input Clock to System PLL * /
       switch (LPC_SYSCON-> SYSPLLCLKSEL & 0x03) {
           case 0: / * Internal RC oscillator * /
             SystemCoreClock = __IRC_OSC_CLK;
             break;
           case 1: / * System oscillator * /
             SystemCoreClock = __SYS_OSC_CLK;
             break;
           case 2: / * Reserved * /
             SystemCoreClock = 0;
             break;
           case 3: / * CLKIN pin * /
             SystemCoreClock = __CLKIN_CLK;
             break;
       }
       break;
     case 2: / * WDT Oscillator * /

 :
 :
     LPC_SYSCON-> SYSAHBCLKDIV = 1 below
     SystemCoreClock / = LPC_SYSCON -> SYSAHBCLKDIV;

As LPC_SYSCON-> MAINCLKSEL = 0 is set in SystemInit, the system clock temporarily becomes _ IRC _ OSC_CLK. After that, it divides by the value of LPC_SYSCON-> SYSAHBCLKDIV, but since it is 1 in the setting, the system clock will be _ IRC _OSC_CLK as it is.

  / * ------------------------------------------------------ ------------------------------
   Define clocks
  * ------------------------------------------------------------------- --------------------------- * /
 #define __XTAL (12000000UL) / * Oscillator frequency * /
 #define __SYS_OSC_CLK (__XTAL) / * Main oscillator frequency * /
 #define __IRC_OSC_CLK (12000000 UL) / * Internal RC oscillator frequency * /
 #define __CLKIN_CLK (12000000 UL) / * CLKIN pin frequency * /

Since 0 __ IRC _ OSC_CLK is 12 MHz from the definition, the system clock is 12 MHz. This is the startup routine. The main requirement in the star tap is as follows.

  • Operation clock setting
  • Setting the block supplying the clock

Learn microcomputer with LPCXpresso and LPC 800 – MAX (Part 3: Examine LED operation (GPIO))

Examining the operation of the sample application (Blinky) LED

With this, it is now possible to debug etc. While analyzing the actual code, I would like to look at ARM Cortex – M0 or the architecture of the LPC 800 series. First of all, I will skip the first half and look at the control section of the LED which is easy to understand. I feel that the following method is almost as it is writing the process of confirming to understand the operation and architecture of these microcomputers.

LED controlled by GPIO

The LEDs are located on the LPC 800 – MAX board and are connected to the LPC 812. Confirm the circuit diagram of LPC 800 – MAX to confirm the connection.

The following part in p2 is the LED circuit. From this circuit diagram

  • PIO 0 _ 16: BLUE
  • PIO 0 _ 17: GREEN
  • PIO 0 _ 7: RED

I understand that.

f:id:tomo_watanabe:20131009215242p:plain

Looking at the source code of Blinky (main.c)

  / * Set port p0.7 to output * /
   GPIOSetDir (0, 7, 1);

   / * Set port p0.16 to output * /
   GPIOSetDir (0, 16, 1);

   / * Set port p0.17 to output * /
   GPIOSetDir (0, 17, 1);

Because it is becoming, you will know the right thing. Looking at this function, registers are properly controlled by AND and OR. dir is set to output = 1.

  (lpc 8 x x _ gpio.c)

 void GPIOSetDir (uint32_t portNum, uint32_t bitPosi, uint32_t dir)
 {
   if (dir)
   {
         LPC_GPIO_PORT -> DIR 0 | = (1 << bit Posi);
   }
   else
   {
         LPC_GPIO_PORT -> DIR 0 & = - (1 << bit Posi);
   }
   return;
 }

Confirm GPIO register

Well, looking for the location pointed to by “LPC_GPIO_PORT” in this function ,,,,

  (LPC 8 x x. H)

 #define LPC_GPIO_PORT_BASE (0xA0000000)
 :
 #define LPC_GPIO_PORT ((LPC_GPIO_PORT_TypeDef *) LPC_GPIO_PORT_BASE)
 :

“LPC_GPIO_PORT” is a pointer to “LPC_GPIO_PORT_BASE” and LPC_GPIO_PORT_BASE = 0xA0000000. I will check this. Check the LPC 81x user’s manual on the LPC 800 series page. Memory map is on p10. According to this, 0xA0000000 to 0xA0004000 are allocated to the GPIO.

f:id:tomo_watanabe:20131009235224p:plain

When looking at LPC_GPIO_PORT_TypeDef on the code, it is defined as follows.

  (LPC 8 x x. H)

 typedef struct {                            
   __IO uint8_t B0 [18]; / *! <(@ 0xA0000000) Byte pin registers port 0 * /
   __I uint 16 _ t RESERVED 0 [2039];
   __IO uint32_t W0 [18]; / *! <(@ 0xA0001000) Word pin registers port 0 * /
        uint32 _ t RESERVED 1 [1006];
   __IO uint32 _ t DIR 0; / * 0 x 2000 * /
        uint32 _ t RESERVED 2 [31];
   __IO uint32_t MASK 0; / * 0x2080 * /
        uint32 _ t RESERVED 3 [31];
   __IO uint32_t PIN0; / * 0x2100 * /
        uint32 _ t RESERVED 4 [31];
   __IO uint32 _ t MPIN 0; / * 0x2180 * /
        uint32 _ t RESERVED 5 [31];
   __IO uint32_t SET0; / * 0x2200 * /
        uint32 _ t RESERVED 6 [31];
   __O uint32 _ t CLR 0; / * 0 x 2280 * /
        uint32_t RESERVED 7 [31];
   __O uint32 _ t NOT 0; / * 0 x 2300 * /

 } LPC_GPIO_PORT_TypeDef;

For definition of the GPIO port, refer to p88 of the user’s manual

f:id:tomo_watanabe:20131009235252p:plain

It will correspond to this. From this table, you can see that the Reset Value of DIR 0 is 0, that is, the initial value at startup is INPUT. In Blinky, 1 (= OUTPUT) is OR written to the corresponding bit of DIR 0.

Also, you can see that SET0, CLR0 and NOT0 are used for writing to GPIO. Since the Reset Value of SET 0 is 0, the state immediately after setting the GPIOSetDir function in Blinky

  • OUTPUT
  • Initial value: 0

Therefore, the corresponding GPIO’s LED will be “lit” . In order to check this on the actual machine, you can confirm by step execution to the GPIOSetDir function. Below is the state immediately after setting DIR of PIO 0 _ 7 (RED).

f:id:tomo_watanabe:20131009223241j:plain

The reason for turning on can be understood by checking the circuit diagram. In the circuit diagram, the LED uses an anode common and is pulled up to 3.3 v. Therefore, when 0 is written with OUTPUT, the current will flow and the LED will light up. When turning off, writing 1 will make the potential equal at 3.3 v and will go out because there is no current flowing.

Writing to GPIO

Writing is done where I understood the setting, but this is what I wrote above. I look at the code of main.c here.

  while (1) / * Loop forever * /
   {
         / * I / O configuration and LED setting pending. * /
         if ((mrt_counter> 0) && (mrt_counter <= 200))
         {
             GPIOSetBitValue (0, 7, 0);
         }
         if ((mrt_counter> 200) && (mrt_counter <= 400))
         {
             GPIOSetBitValue (0, 7, 1);
         }

Simply set the GPIOSetBitValue function to 0 for lighting and 1 for extinguish. The function to set is the same as GPIOSetDir. I am using SET / CLR here.

  (lpc 8 x x _ gpio.c)

 void GPIOSetBitValue (uint32_t portNum, uint32_t bitPosi, uint32_t bitVal)
 {
   if (bitVal)
   {
         LPC_GPIO_PORT -> SET 0 = 1 << bit Posi;
   }
   else
   {
         LPC_GPIO_PORT-> CLR 0 = 1 << bit Posi;
   }
   return;
 }

Initial setting of GPIO

I had skipped it, but I also look at the initial setting of GPIO.

  / * Enable AHB clock to the GPIO domain. * /
   LPC_SYSCON -> SYSAHBCLKCTRL | = (1 << 6);

Look for “LPC_SYSCON” and “SYSAHBCLKCTRL” in the same way as you searched for in the GPIO. This is the “System clock control” register of “System configuration”. (User’s Manual p 26, p 35) And 1 is written at the 6 th bit.

f:id:tomo_watanabe:20131009235347p:plain

From this table you can see that GPIO block is enabled by enabling clock supply to GPIO.


It is a tricky difference between Arduino and Arduino (^ ^; Just moving one GPIO will require investigation and understanding this much.The next time I look at the MRT (Multi rate timer) and around the clock I guess it is this.

Learn microcomputer with LPCXpresso and LPC 800 – MAX (Part 2: Use printf statement for debugging)

Although online debugging can be done normally, I tried using only one printf statement.

Use printf statement for debugging

If you write the printf statement in the previous Blinky project and build it, it will result in an error with the linker as shown below.

f:id:tomo_watanabe:20131009211938p:plain

When I looked it up, the solution was written in “Hobby engineering” here.

From the project window right click on the project of “Blinky” → “Properties” → ” C / C ++ Build” → “Settings” select “MCU Linker” → “Target” in the right view.

Since “Use C Library” is “Redlib (none)”, change this to “Redlib (semihost)” (see the figure below)

f:id:tomo_watanabe:20131009213149p:plain

Building with this …

f:id:tomo_watanabe:20131009213319p:plain

The build has passed successfully. However, please be careful as this setting seems necessary for each project.

When actually executing it, the content of printf will be displayed in the “Console” window.

f:id:tomo_watanabe:20131009213814p:plain

I will write about setting of GPIO register of Blinky, but separate entry separately.